介绍

在Fragment之前,我们通常把一个Activity作为一个页面。
但随着页面元素的增加以及场景的复杂,单个页面已经不能满足需要,在屏幕上通常要同
时展示多个区域、多个页面内容,这些内容的切换通常是整体的。
因此,为了让屏幕展示更多内容,以及对这些内容统一管理,引入了Fragment。

  • Fragment,就是将一块内容区域封装在一起,统一管理,构成一个Fragment。
  • Fragment是依附在Activity上而存在的。一个Activity中可以有多个Fragment,各个Fragment之间可以传递数据、互相切换。
  • Fragment与Activity很相似,也有生命周期函数

设置环境

在应用的 build.gradle 文件中添加以下依赖项:

dependencies {
    val fragment_version = "1.8.1"

    // Java language implementation
    implementation("androidx.fragment:fragment:$fragment_version")
    // Kotlin
    implementation("androidx.fragment:fragment-ktx:$fragment_version")
}

创建

静态创建

  1. 创建 Fragment 类及其布局文件。
  2. 在活动的布局文件中使用 <androidx.fragment.app.FragmentContainerView>fragment标签引用 Fragment。

注意使用的是androidx.fragment.app.Fragment

具体流程

创建 Fragment 类及其布局文件

  1. 自动生成了ExampleFragment类及其布局文件

    这是一个自定义的类继承自 Fragment ,你可以在这个类中定义 fragment 的行为和 UI。

在活动的布局文件中添加 Fragment

  1. 新建一个类(比如MainActivity),因为fragment需要依赖于activity。在该类的布局文件中添加 Fragment容器视图(或者使用FragmentContainerView容器也可以)
  • 注意添加 android:nameclass 属性来指定要加载的 Fragment
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".fragment.StaticFragment1">

    <!-- 添加一个fragment,用于显示StaticFragment类的实例 -->
    <!-- 通过android:name属性指定fragment的类名 -->
    <!-- 通过android:id属性为fragment指定一个ID,以便在代码中引用 -->
    <fragment
        android:id="@+id/fragment"
	   android:name="com.example.fragmentpractice_726.fragment.exampleFragment1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout="@layout/fragment_example1"/>
    
    <!-- 或者使用 FragmentContainerView -->
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="com.example.fragmentpractice.fragment.ExampleFragment" />

</LinearLayout>

使用 Fragment

  1. ExampleFragment 类的布局文件中设计UI,并在 ExampleFragment 类中设置交互逻辑

注意

fragment标签和FragmentContainerView标签

  • fragment必须声明android:id或者android:tag属性,否则会有错

  • FragmentContainerView必须声明android:id属性

  • tools:layout = "@layout/example fragment",可在预览视图中看到fragment预览界

  • android:name属性也可以用class代替,

class="com.example.fragmentpractice.fragment.StaticFragment1"

动态创建

  1. 创建Fragment类及其布局文件
  2. Activity的布局文件中准备容器
  3. Activity中动态添加Fragment

创建Fragment类及其布局文件

在Activity的布局文件中准备容器

可以使用FragmentContainerViewFrameLayout

设置一个id,以便动态创建获取

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/fragment_container2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

在Activity中动态添加Fragment

使用FragmentManagerFragmentTransaction将Fragment添加到Activity中

  • Fragment Manager

每个 Activiy 都有一个 FragmentManager,用来管理它所包含的 Fragment。在使用支持库时,将使用getSupportFragmentManger 方法来访问FragmentManager

  • Fragment Transaction
    FragmentTransaction 用于添加、删除和替换 Fragment。使用 Fragment Transaction,可以使布局具有动态性
    也就是说,它们将根据用户交互和应用状态进行调整和更改。

使用 Fragment ManagerbeginTransaction 方法创建新的 Fragment Transaction

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        if (savedInstanceState == null) {
            // 检查是否是第一次创建Activity实例,防止重复添加Fragment
            FragmentManager fragmentManager = getSupportFragmentManager();
            // 获取FragmentManager以管理Fragments

            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            // 开启一个Fragment事务,以添加、移除或替换Fragment

            fragmentTransaction.add(R.id.fragment_container2, ExampleFragment2.class, null);
            // 将ExampleFragment2添加到指定的容器(R.id.fragment_container2)
            // 第一个参数是Fragment容器的ID
            // 第二个参数是Fragment类
            // 第三个参数是传递给Fragment的可选参数,这里为null

            fragmentTransaction.commit();
            // 提交Fragment事务,应用所有更改
        }
    }
}

生命周期

尽管 Fragment 的生命周期与其所属的 Activity 相关,但它在标准 Activity 生命周期中也有自己的特点。它包括基本的 Activity 生命周期方法,例如 onResume ,但与 Activity 交互和 UI 生成相关的方法也很重要。

被调用以将fragment恢复到恢复状态(与用户交互)的一系列核心生命周期方法是:

  1. onAttach一旦fragment与其活动关联,就会调用。
  2. onCreate 被调用来初始创建fragment。
  3. onCreateView 创建并返回与fragment关联的视图层次结构。
  4. onViewCreated可以在视图已经创建但还未显示时进行一些操作
  5. onActivityCreated 在Activity的onCreate方法调用后
  6. onStart 使fragment对用户可见(基于其包含的活动正在启动)。
  7. onResume 使fragment开始与用户交互(基于其包含的活动正在恢复)。

当fragment不再被使用时,它会经历一系列相反的回调:

  1. onPause fragment不再与用户交互,因为其活动已暂停或fragment操作正在活动中对其进行修改。
  2. onStop fragment不再对用户可见,因为其活动已停止或fragment操作正在活动中修改它。
  3. onDestroyView 允许fragment清理与其视图关联的资源。
  4. onDestroy 调用以对fragment状态进行最终清理。
  5. onDetach 在fragment不再与其活动关联之前调用。
da95a1b40c8c9dd4360ea8c6c9a9c274

Fragment操作

添加

一个容器里可以添加多个Fragment,依次盖在上面,类比FrameLayout

注意:由于事件分发机制,同时添加多个Fragment时,在空白处点击会产生穿透的效果,也就是作用到下层的Fragment

解决方法:在Fragment里拦截onTouch事件。

  • 最好不要用add方式,而用replace添加fragment,保证容器中里只有一个Fragment

添加的方法

 FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
  1. 使用Fragment的类名来添加Fragment并且添加到回退栈中
 fragmentTransaction.add(R.id.fragment_container2, ExampleFragment2.class, null).addToBackStack(null).commit();
  1. 使用 Fragment 实例添加 Fragment
 ExampleFragment2 fragment2 = new ExampleFragment2();
            fragmentTransaction.add(R.id.fragment_container2, fragment2).addToBackStack(null).commit();

返回栈

点击手机的back按钮会依次弹出BackStack中的Fragment,而不是直接退出Activity。

addToBackStack()参数:

是用于标记回退栈中的事务的标签。这个标签可以用于以后对回退栈中事务的查找和管理。不是返回栈的名字

传递 null,则不会对事务进行标记。这个事务会被简单地添加到回退栈中。

查找

  1. 根据 id 查找

    Fragment fragment = fragmentManager.findFragmentById(R.id.fragment);
    
    • findFragmentById 方法根据提供的 id 查找 Fragment
    • 如果找到多个Fragment,它将返回最上面的一个。
  2. 根据 tag 查找

    Fragment fragment = fragmentManager.findFragmentByTag("fragment");
    
    • findFragmentByTag 方法根据提供的 tag 查找 Fragment
    • 如果有多个Fragment使用相同的标签,它将返回最上面的一个。

查找逻辑

  • 如果 Fragment 没有在当前容器中找到,它会继续在回退栈(BackStack)中查找。
  • 回退栈中的 Fragment 是按照添加顺序存储的,findFragmentByIdfindFragmentByTag 方法会返回最上面的一个。
  • 如果 Fragment 不在当前容器和回退栈中,方法会返回 null

删除

fragmentTransaction.remove(fragment).commit();

该方法不会将 Fragment 从回退栈中移除,Fragment 的状态仍然保留在回退栈中。只有按返回键或调用 FragmentManagerpopBackStack 方法,Fragment 才会被彻底移除。

替换

使用 FragmentTransactionreplace 方法可以用新的 Fragment 替换当前容器中的 Fragment。这会先移除当前容器中所有Fragment,然后添加新的 Fragment

fragmentTransaction.replace(R.id.fragment_container, ReplaceFragment.class, null).commit();

移除当前容器中所有的 Fragment,然后添加新的 Fragment

带回退栈情况

fargment移除了,但回退栈没有移除,使用返回键界面不会变化

  • 如果你使用 replace 方法,默认情况下,新添加的 Fragment 会覆盖旧的 Fragment
  • 可以使用 addToBackStack 方法将 replace 操作添加到回退栈中,这样用户可以通过按返回键回到之前的 Fragment

示例:使用 replaceaddToBackStack

FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null); // 将事务添加到回退栈
transaction.commit();

显示与隐藏

fragmentTransaction.show(yourFragment).commit();
fragmentTransaction.hide(yourFragment).commit();
fragmentTransaction.attach(yourFragment).commit();
fragmentTransaction.detach(yourFragment).commit();
操作Fragment的变化
Show/Hide仅隐藏或显示View,Fragment的状态和实例保持不变
Attach/Detach仅销毁View,Fragment仍保存状态,不与Activity关联,允许后续重新显示。
Add/Remove销毁View和整个Fragment,使其状态完全消失,不可恢复
  • Show/Hide:适用于需要频繁切换显示的用户界面,比如标签页。

  • Attach/Detach:适用于当Fragment需要暂时不可见,但不想重新创建的情形。

  • Add/Remove:在需要管理Fragment的生命周期和状态,且Fragment的使用是可选的场景最为合适。
    ew,Fragment的状态和实例保持不变 |
    | Attach/Detach | 仅销毁View,Fragment仍保存状态,不与Activity关联,允许后续重新显示。 |
    | Add/Remove | 销毁View和整个Fragment,使其状态完全消失,不可恢复 |

  • Show/Hide:适用于需要频繁切换显示的用户界面,比如标签页。

  • Attach/Detach:适用于当Fragment需要暂时不可见,但不想重新创建的情形。

  • Add/Remove:在需要管理Fragment的生命周期和状态,且Fragment的使用是可选的场景最为合适。



感谢您的阅读
如有错误烦请指正


参考:

1.1-Activity通过方法向Fragment传递数据_哔哩哔哩_bilibili
2. 《第一行代码》

更多推荐