在运行时,FragmentManager
可以响应用户交互来添加、移除、替换 Fragment 并对其执行其他操作。您提交的每组 Fragment 变更都称为事务,您可以使用 FragmentTransaction
类提供的 API 指定事务内部的操作。您可以将多个操作分组到一个事务中,例如,一个事务可以添加或替换多个 Fragment。当您在同一屏幕上显示多个同级 Fragment 时(例如分屏视图),此分组非常有用。
您可以将每个事务保存到由 FragmentManager
管理的返回栈中,允许用户向后导航 Fragment 变更(类似于向后导航 activity)。
您可以从 FragmentManager
调用 beginTransaction()
来获取 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()
等同于调用 remove()
并替换容器中的 Fragment,然后将新 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()
不会立即执行事务。相反,事务被安排在主 UI 线程能够执行时尽快运行。但是,如有必要,您可以调用 commitNow()
以立即在 UI 线程上运行 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()
分隔。