Во время выполнения FragmentManager
может добавлять, удалять, заменять фрагменты и выполнять другие действия с фрагментами в ответ на взаимодействие с пользователем. Каждый набор изменений фрагмента, который вы фиксируете, называется транзакцией , и вы можете указать, что делать внутри транзакции, используя API, предоставляемые классом FragmentTransaction
. Вы можете сгруппировать несколько действий в одну транзакцию — например, транзакция может добавить или заменить несколько фрагментов. Эта группировка может быть полезна, когда на одном экране отображается несколько одноуровневых фрагментов, например, в разделенных представлениях.
Вы можете сохранить каждую транзакцию в обратном стеке, управляемом FragmentManager
, что позволяет пользователю перемещаться назад по изменениям фрагмента — аналогично переходу назад по действиям.
Вы можете получить экземпляр FragmentTransaction
из FragmentManager
, вызвав beginTransaction()
, как показано в следующем примере:
Котлин
val fragmentManager = ... val fragmentTransaction = fragmentManager.beginTransaction()
Ява
FragmentManager fragmentManager = ... FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Последний вызов каждого FragmentTransaction
должен подтвердить транзакцию. Вызов commit()
сигнализирует FragmentManager
о том, что все операции были добавлены в транзакцию.
Котлин
val fragmentManager = ... // The fragment-ktx module provides a commit block that automatically // calls beginTransaction and commit for you. fragmentManager.commit { // Add operations here }
Ява
FragmentManager fragmentManager = ... FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); // Add operations here fragmentTransaction.commit();
Разрешить изменение порядка изменений состояния фрагмента
Каждая FragmentTransaction
должна использовать setReorderingAllowed(true)
:
Котлин
supportFragmentManager.commit { ... setReorderingAllowed(true) }
Ява
FragmentManager fragmentManager = ... fragmentManager.beginTransaction() ... .setReorderingAllowed(true) .commit();
Для совместимости поведения флаг переупорядочения по умолчанию не включен. Однако это необходимо, чтобы позволить FragmentManager
правильно выполнить ваш FragmentTransaction
, особенно когда он работает с обратным стеком и запускает анимацию и переходы. Включение флага гарантирует, что если несколько транзакций выполняются одновременно, любые промежуточные фрагменты (т. е. те, которые добавляются, а затем немедленно заменяются) не претерпевают изменений жизненного цикла или не выполняются их анимации или переходы. Обратите внимание, что этот флаг влияет как на первоначальное выполнение транзакции, так и на ее отмену с помощью popBackStack()
.
Добавление и удаление фрагментов
Чтобы добавить фрагмент в FragmentManager
, вызовите add()
для транзакции. Этот метод получает идентификатор контейнера для фрагмента, а также имя класса фрагмента, который вы хотите добавить. Добавленный фрагмент переводится в состояние RESUMED
. Настоятельно рекомендуется, чтобы контейнер представлял собой FragmentContainerView
, который является частью иерархии представлений.
Чтобы удалить фрагмент с хоста, вызовите метод remove()
, передав экземпляр фрагмента, полученный из менеджера фрагментов, с помощью findFragmentById()
или findFragmentByTag()
. Если представление фрагмента ранее было добавлено в контейнер, на этом этапе представление удаляется из контейнера. Удаленный фрагмент переводится в состояние DESTROYED
.
Используйте replace()
чтобы заменить существующий фрагмент в контейнере экземпляром нового класса фрагмента, который вы предоставляете. Вызов replace()
эквивалентен вызову remove()
с фрагментом в контейнере и добавлению нового фрагмента в тот же контейнер.
Следующий фрагмент кода показывает, как можно заменить один фрагмент другим:
Котлин
// 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) }
Ява
// 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
.
По умолчанию изменения, внесенные в FragmentTransaction
, не добавляются в задний стек. Чтобы сохранить эти изменения, вы можете вызвать addToBackStack()
в FragmentTransaction
. Дополнительные сведения см. в разделе Менеджер фрагментов .
Фиксация является асинхронной
Вызов commit()
не выполняет транзакцию немедленно. Скорее, транзакция будет запущена в основном потоке пользовательского интерфейса, как только она сможет это сделать. Однако при необходимости вы можете вызвать commitNow()
, чтобы немедленно запустить транзакцию фрагмента в потоке пользовательского интерфейса.
Обратите внимание, что commitNow
несовместим с addToBackStack
. В качестве альтернативы вы можете выполнить все ожидающие FragmentTransactions
отправленные вызовами commit()
, которые еще не выполнялись, вызвав executePendingTransactions()
. Этот подход совместим с addToBackStack
.
Для подавляющего большинства случаев использования commit()
— это все, что вам нужно.
Порядок операций важен
Порядок выполнения операций внутри FragmentTransaction
имеет важное значение, особенно при использовании setCustomAnimations()
. Этот метод применяет заданную анимацию ко всем операциям с фрагментами, которые следуют за ним.
Котлин
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 }
Ява
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()
Ограничить жизненный цикл фрагмента
FragmentTransactions
может влиять на состояние жизненного цикла отдельных фрагментов, добавленных в область транзакции. При создании FragmentTransaction
setMaxLifecycle()
устанавливает максимальное состояние для данного фрагмента. Например, ViewPager2
использует setMaxLifecycle()
чтобы ограничить фрагменты за кадром состоянием STARTED
.
Отображение и скрытие видов фрагмента
Используйте методы FragmentTransaction
show()
hide()
чтобы показать и скрыть представление фрагментов, добавленных в контейнер. Эти методы устанавливают видимость представлений фрагмента , не влияя на жизненный цикл фрагмента.
Хотя вам не нужно использовать транзакцию фрагмента для переключения видимости представлений внутри фрагмента, эти методы полезны в тех случаях, когда вы хотите, чтобы изменения состояния видимости были связаны с транзакциями в обратном стеке.
Прикрепление и отсоединение фрагментов
Метод FragmentTransaction
detach()
отделяет фрагмент от пользовательского интерфейса, разрушая его иерархию представлений. Фрагмент остается в том же состоянии ( STOPPED
), как и при помещении его в задний стек. Это означает, что фрагмент был удален из пользовательского интерфейса, но по-прежнему управляется менеджером фрагментов.
Метод attach()
повторно присоединяет фрагмент, от которого он был ранее отсоединен. Это приводит к воссозданию иерархии представлений, прикреплению к пользовательскому интерфейсу и отображению.
Поскольку FragmentTransaction
рассматривается как единый атомарный набор операций, вызовы detach
и attach
к одному и тому же экземпляру фрагмента в одной транзакции эффективно компенсируют друг друга, что позволяет избежать разрушения и немедленного воссоздания пользовательского интерфейса фрагмента. Используйте отдельные транзакции, разделенные функцией executePendingOperations()
, если вы используете commit()
, если вы хотите отсоединить, а затем немедленно повторно присоединить фрагмент.