在运行时,FragmentManager
可以通过 Fragment 执行添加、移除、替换以及其他操作,以响应用户互动。您提交的每组 Fragment 更改称为一个“事务”,并且您可以使用 FragmentTransaction
类提供的 API 指定在事务内需执行何种操作。您可以将多个操作分组到一个事务中。例如,通过一个事务就可以添加或替换多个 Fragment。当您在同一个屏幕上显示多个同级 Fragment(例如使用分块视图)时,该分组会很实用。
您也可将每个事务保存到由 FragmentManager
管理的返回堆栈内,从而让用户能够回退 Fragment 更改(类似于回退 Activity)。
您可以通过调用 beginTransaction()
从 FragmentManager
获取 FragmentTransaction
实例,如以下示例所示:
Kotlin
val fragmentManager = ... val fragmentTransaction = fragmentManager.beginTransaction()
Java
FragmentManager fragmentManager = ... FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
每个 FragmentTransaction
上的最终调用必须提交事务。commit()
调用会向 FragmentManager
发出信号,指明所有操作均已添加到事务中。
Kotlin
val fragmentManager = ... // The fragment-ktx module provides a commit block that automatically // calls beginTransaction and commit for you. fragmentManager.commit { // Add operations here }
Java
FragmentManager fragmentManager = ... FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); // Add operations here fragmentTransaction.commit();
允许对 Fragment 状态更改进行重新排序
每个 FragmentTransaction
都应使用 setReorderingAllowed(true)
:
Kotlin
supportFragmentManager.commit { ... setReorderingAllowed(true) }
Java
FragmentManager fragmentManager = ... fragmentManager.beginTransaction() ... .setReorderingAllowed(true) .commit();
对于行为兼容性,重新排序标志默认处于停用状态。但是,您必须允许 FragmentManager
正确执行 FragmentTransaction
,尤其是它在返回堆栈上操作并运行动画和转换时。启用此标记可确保,如果多个事务一起执行,任何中间 Fragment(即添加然后立即被替换的 Fragment)不会经历生命周期改变,也不会执行动画或转换。请注意,此标志会影响事务的初始执行,也会影响使用 popBackStack()
对事务进行的逆转操作。
添加和移除 Fragment
如需将 Fragment 添加到 FragmentManager
,请对事务调用 add()
。此方法会收到用于存储此 Fragment 的容器的 ID,以及您要添加的 Fragment 的类名。添加的 Fragment 会转为 RESUMED
状态。强烈建议容器为 FragmentContainerView
(视图层次结构的一部分)。
如需从宿主中移除 Fragment,请调用 remove()
,同时传入通过 findFragmentById()
或 findFragmentByTag()
从 Fragment 管理器检索到的 Fragment 实例。
如果 fragment 的视图之前已添加到容器中,此时系统会将该视图从容器中移除。移除的 fragment 会转为 DESTROYED
状态。
使用 replace()
将容器中现有的 Fragment 替换为您提供的新 Fragment 类的实例。调用 replace()
等同于对容器中的 Fragment 调用 remove()
后将新的 Fragment 添加到同一容器中。
以下代码段展示了如何将一个 Fragment 替换为另一个 Fragment:
Kotlin
// Create new fragment val fragmentManager = // ... // Create and commit a new transaction fragmentManager.commit { setReorderingAllowed(true) // Replace whatever is in the fragment_container view with this fragment replace<ExampleFragment>(R.id.fragment_container) }
Java
// Create new fragment and transaction FragmentManager fragmentManager = ... FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.setReorderingAllowed(true); // Replace whatever is in the fragment_container view with this fragment transaction.replace(R.id.fragment_container, ExampleFragment.class, null); // Commit the transaction transaction.commit();
在此示例中,ExampleFragment
的新实例将替换当前由 R.id.fragment_container
标识的布局容器中的 Fragment(如有)。
默认情况下,在 FragmentTransaction
中所做的更改不会添加到返回堆栈。如需保存这些更改,您可以对 FragmentTransaction
调用 addToBackStack()
。如需了解详情,请参阅 Fragment 管理器。
提交操作为异步操作
调用 commit()
不会立即执行事务,而是会将事务调度为能在主界面线程上运行就在主界面线程上运行。但是,您可以在必要时调用 commitNow()
以立即在您的界面线程上运行 Fragment 事务。
请注意,commitNow
与 addToBackStack
不兼容。或者,您也可以通过调用 executePendingTransactions()
执行由 commit()
调用提交的尚未运行的所有待处理 FragmentTransactions
。这种处理方式与 addToBackStack
兼容。
对于绝大多数用例,只需 commit()
即可。
操作排序非常重要
在 FragmentTransaction
中执行操作的顺序至关重要,尤其是在使用 setCustomAnimations()
时。此方法将给定动画应用于遵守该方法的所有 Fragment 操作。
Kotlin
supportFragmentManager.commit { setCustomAnimations(enter1, exit1, popEnter1, popExit1) add<ExampleFragment>(R.id.container) // gets the first animations setCustomAnimations(enter2, exit2, popEnter2, popExit2) add<ExampleFragment>(R.id.container) // gets the second animations }
Java
getSupportFragmentManager().beginTransaction() .setCustomAnimations(enter1, exit1, popEnter1, popExit1) .add(R.id.container, ExampleFragment.class, null) // gets the first animations .setCustomAnimations(enter2, exit2, popEnter2, popExit2) .add(R.id.container, ExampleFragment.class, null) // gets the second animations .commit()
限制 Fragment 的生命周期
FragmentTransactions
会影响在事务的作用域内添加的各个 Fragment 的生命周期状态。创建 FragmentTransaction
时,setMaxLifecycle()
会设置给定 Fragment 的最大生命周期状态。例如,ViewPager2
使用 setMaxLifecycle()
将屏幕外 Fragment 的最大生命周期状态限定为 STARTED
状态。
显示和隐藏 Fragment 的视图
分别使用 FragmentTransaction
方法 show()
和 hide()
显示和隐藏已添加至容器的 Fragment 视图。这些方法可设置 Fragment 视图的可见性,而不会影响 Fragment 的生命周期。
虽然您无需使用 Fragment 事务切换 Fragment 中视图的可见性,但当需要对可见性状态进行更改从而与返回堆栈上的事务关联时,这些方法很有用。
附加和分离 Fragment
FragmentTransaction
方法 detach()
用于将 Fragment 与界面分离,从而销毁其视图层次结构。Fragment 所处状态 (STOPPED
) 保持不变,与将其放入返回堆栈时的状态相同。这意味着 Fragment 已从界面中移除,但仍由 Fragment 管理器管理。
attach()
方法会重新附加之前分离的 Fragment。这会导致视图层次结构重新创建,附加到界面并显示。
由于 FragmentTransaction
被视为单个原子操作集,对同一事务中的同一 Fragment 实例同时调用 detach
和 attach
可以有效地相互抵消,因此这可以避免销毁并立即重新创建 Fragment 界面。如需在分离后立即重新附加 Fragment,请使用单独的事务(如使用 commit()
,则由 executePendingOperations()
分离)。