W czasie działania FragmentManager
w odpowiedzi na interakcję użytkownika może dodawać, usuwać i zastępować fragmenty oraz wykonywać na nich inne działania. Każdy przesyłany zestaw zmian fragmentów jest nazywany transakcją. Za pomocą interfejsów API dostarczanych przez klasę FragmentTransaction
możesz określić, co ma się stać w obrębie transakcji. Możesz zgrupować wiele działań w jedną transakcję, na przykład transakcja może dodawać lub zastępować wiele fragmentów. Takie grupowanie może być przydatne, gdy wiele fragmentów równorzędnych jest wyświetlanych na tym samym ekranie, np. w widokach podzielonych.
Każdą transakcję możesz zapisać w stosie wstecznym zarządzanym przez FragmentManager
, co pozwoli użytkownikowi przejść wstecz przez zmiany fragmentów – podobnie jak w przypadku przechodzenia wstecz po działaniach.
Instancję FragmentTransaction
można pobrać z FragmentManager
, wywołując beginTransaction()
, jak w tym przykładzie:
Kotlin
val fragmentManager = ... val fragmentTransaction = fragmentManager.beginTransaction()
Java
FragmentManager fragmentManager = ... FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Ostatnie wywołanie każdego FragmentTransaction
musi zatwierdzić transakcję.
Wywołanie commit()
sygnalizuje interfejs FragmentManager
, że wszystkie operacje zostały dodane do transakcji.
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();
Zezwalaj na zmianę kolejności zmian stanu fragmentu
Każdy element FragmentTransaction
powinien używać parametru setReorderingAllowed(true)
:
Kotlin
supportFragmentManager.commit { ... setReorderingAllowed(true) }
Java
FragmentManager fragmentManager = ... fragmentManager.beginTransaction() ... .setReorderingAllowed(true) .commit();
Ze względu na zgodność działania flaga zmiany kolejności jest domyślnie wyłączona.
Jest jednak wymagane, aby umożliwić FragmentManager
prawidłowe wykonanie FragmentTransaction
, zwłaszcza gdy działa ona na stosie wstecznym i uruchamia animacje oraz przejścia. Włączenie tej flagi daje pewność, że w przypadku jednoczesnego wykonywania wielu transakcji wszystkie fragmenty pośrednie (tj. te, które zostały dodane, a następnie natychmiast zastąpione) nie będą się zmieniać w cyklu życia ani nie będą wykonywane ich animacje lub przejścia. Pamiętaj, że ta flaga wpływa zarówno na początkowe wykonanie transakcji, jak i na cofanie transakcji z użyciem funkcji popBackStack()
.
Dodawanie i usuwanie fragmentów
Aby dodać fragment do FragmentManager
, wywołaj metodę add()
w transakcji. Ta metoda otrzymuje identyfikator kontenera dla danego fragmentu oraz nazwę klasy fragmentu, który chcesz dodać. Dodany fragment zostanie przeniesiony do stanu RESUMED
. Zdecydowanie zalecamy, aby kontener był FragmentContainerView
, który jest częścią hierarchii widoków.
Aby usunąć fragment z hosta, wywołaj metodę remove()
, przekazując do instancji fragmentu pobranej z menedżera fragmentów za pomocą metody findFragmentById()
lub findFragmentByTag()
.
Jeśli widok fragmentu został wcześniej dodany do kontenera, zostanie on z niego usunięty. Usunięty fragment jest przenoszony do stanu DESTROYED
.
Za pomocą metody replace()
możesz zastąpić istniejący fragment w kontenerze wystąpieniem nowej, podanej przez Ciebie klasy fragmentu. Wywołanie replace()
jest równoważne wywołaniu remove()
z fragmentem w kontenerze i dodaniu do tego samego kontenera nowego fragmentu.
Ten fragment kodu pokazuje, jak zastąpić jeden fragment innym:
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();
W tym przykładzie nowe wystąpienie obiektu ExampleFragment
zastępuje fragment, który znajduje się obecnie w kontenerze układu oznaczonym przez R.id.fragment_container
.
Domyślnie zmiany wprowadzone w FragmentTransaction
nie są dodawane do stosu wstecznego. Aby zapisać te zmiany, możesz wywołać metodę addToBackStack()
w usłudze FragmentTransaction
. Więcej informacji znajdziesz w sekcji Menedżer fragmentów.
Zatwierdzenie jest asynchroniczne
Wywołanie commit()
nie przeprowadza transakcji od razu. Transakcja powinna być raczej uruchomiona w głównym wątku interfejsu, gdy tylko będzie to możliwe. W razie potrzeby możesz jednak od razu uruchomić transakcję dotyczącą fragmentu w wątku UI, używając wywołania commitNow()
.
Pamiętaj, że dyrektywa commitNow
jest niezgodna z addToBackStack
. Możesz też wykonać wszystkie oczekujące wywołania FragmentTransactions
przesłane przez wywołania commit()
, które nie zostały jeszcze uruchomione, używając wywołania executePendingTransactions()
. Ta metoda jest zgodna z tymi zasadami: addToBackStack
.
W większości przypadków wystarczy Ci commit()
.
Kolejność operacji jest istotna
Kolejność wykonywania operacji w obrębie FragmentTransaction
jest istotna, zwłaszcza gdy korzystasz z setCustomAnimations()
. Ta metoda stosuje podane animacje do wszystkich operacji na fragmentach, które po nich występują.
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()
Ogranicz cykl życia fragmentu
FragmentTransactions
może wpływać na stan cyklu życia poszczególnych fragmentów dodanych w zakresie transakcji. Podczas tworzenia elementu FragmentTransaction
setMaxLifecycle()
ustawia maksymalny stan danego fragmentu. Na przykład ViewPager2
używa setMaxLifecycle()
, aby ograniczać fragmenty poza ekranem do stanu STARTED
.
Pokazywanie i ukrywanie widoków fragmentu
Użyj metod FragmentTransaction
show()
i hide()
, aby wyświetlać i ukrywać widok fragmentów dodanych do kontenera.
Te metody ustawiają widoczność widoków fragmentu bez wpływu na cykl życia fragmentu.
Chociaż nie musisz używać transakcji na fragment do przełączania widoczności widoków w obrębie danego fragmentu, te metody są przydatne w przypadkach, gdy chcesz powiązać zmiany stanu widoczności z transakcjami w stosie wstecznym.
Dołączanie i odłączanie fragmentów
Metoda FragmentTransaction
detach()
odłącza fragment z interfejsu, niszcząc jego hierarchię widoków. Fragment pozostaje w tym samym stanie (STOPPED
) co po umieszczeniu na stosie tylnym.
Oznacza to, że dany fragment został usunięty z interfejsu, ale nadal jest zarządzany przez menedżera fragmentów.
Metoda attach()
ponownie dołącza fragment, od którego został wcześniej odłączony.
W ten sposób jej hierarchia widoków zostanie odtworzona, dołączona do interfejsu użytkownika i wyświetlona.
Gdy obiekt FragmentTransaction
jest traktowany jako pojedynczy, niepodzielny zbiór operacji, wywołania detach
i attach
w tym samym wystąpieniu fragmentu w tej samej transakcji skutecznie anulują się wzajemnie, co pozwala uniknąć zniszczenia i natychmiastowego odtwarzania UI fragmentu. Jeśli chcesz odłączyć, a następnie natychmiast ponownie dołączyć fragment, użyj osobnych transakcji rozdzielonych znakiem executePendingOperations()
, jeśli używasz atrybutu commit()
.