片段交易

在執行階段,FragmentManager 可根據使用者互動內容來新增、移除、取代及執行其他包含片段的動作。您修訂的每組片段變更都稱為「交易」,且您可以使用 FragmentTransaction 類別提供的 API 指定交易過程中要執行的作業。您可以將多個動作分入單一交易。舉例來說,某個交易可新增或取代多個片段。如要在同一畫面上顯示多個同層片段 (例如分割檢視),這種分組做法就會很實用。

您可以將每個交易儲存至由 FragmentManager 管理的返回堆疊,讓使用者透過片段變更返回瀏覽 (原理類似瀏覽先前的活動)。

您可以呼叫 beginTransaction() 來取得 FragmentManagerFragmentTransaction 例項,如以下範例所示:

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();

允許重新排序片段狀態變更

每個 FragmentTransaction 都應使用 setReorderingAllowed(true)

Kotlin

supportFragmentManager.commit {
    ...
    setReorderingAllowed(true)
}

Java

FragmentManager fragmentManager = ...
fragmentManager.beginTransaction()
    ...
    .setReorderingAllowed(true)
    .commit();

為了提供行為相容性,系統預設不會啟用重新排序標記。但如果想讓 FragmentManager 正確執行 FragmentTransaction (尤其是當其在返回堆疊中運作,並會執行動畫和轉換時),就必須啟用這個標記。啟用這個標記後,如果有多個共同執行的交易,任何中繼片段 (例如新增後立即遭到取代的片段) 都一定不會經歷生命週期變更,系統也一定不會執行這些片段的動畫或轉換。請注意,如果啟用這個標記,交易的初始執行作業和透過 popBackStack() 進行的交易反轉作業都會受到影響。

新增和移除片段

如要將片段新增至 FragmentManager,請針對交易呼叫 add()。這個方法會接收片段「容器」的 ID,以及待新增片段的類別名稱。新增的片段會移至 RESUMED 狀態。我們強烈建議您將「容器」視為屬於檢視區塊階層一部分的 FragmentContainerView

如要從主機中移除片段,請呼叫 remove(),傳入透過 findFragmentById()findFragmentByTag() 從片段管理員擷取的片段例項。如果片段的檢視區塊先前已新增至容器,系統會在這個階段將該檢視區塊從容器中移除。遭移除的片段會移至 DESTROYED 狀態。

使用 replace(),將容器中現有的片段取代為您提供的新片段類別例項。呼叫 replace() 就等同於呼叫容器中含有片段的 remove() 並在該容器中新增片段。

以下程式碼片段說明如何將某個片段取代為其他片段:

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 識別的片段 (如果有的話)。

根據預設,在 FragmentTransaction 中所做的變更不會新增至返回堆疊。如要儲存這些變更,您可以針對 FragmentTransaction 呼叫 addToBackStack()。詳情請參閱「片段管理員」一文。

修訂作業為非同步性質

呼叫 commit() 後,系統不會立即執行交易,而會安排盡快在主要 UI 執行緒中執行交易。不過,您可以視需要呼叫 commitNow(),立即在 UI 執行緒中執行片段交易。

請注意,commitNowaddToBackStack 不相容。或者,您也可以呼叫 executePendingTransactions(),藉此執行已由 commit() 提交但尚未執行的所有待處理 FragmentTransactions。這個做法與 addToBackStack 相容。

對大多數用途而言,您只要使用 commit() 即可。

作業順序相當重要

FragmentTransaction 中的作業執行順序相當重要,尤其是使用 setCustomAnimations() 時。這個方法會將特定動畫套用至後續所有的片段作業。

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()

限制片段的生命週期

針對交易範圍內新增的個別片段,FragmentTransactions 可能會影響其生命週期狀態。建立 FragmentTransaction 時,setMaxLifecycle() 會設定特定片段的狀態上限。例如,ViewPager2 會使用 setMaxLifecycle() 將螢幕外片段限制為 STARTED 狀態。

顯示和隱藏片段的檢視區塊

使用 FragmentTransaction 方法 show()hide() 來顯示/隱藏已新增至容器的片段檢視區塊。這些方法會改變片段檢視區塊的顯示設定,而「不會」影響片段的生命週期。

雖然您不需要使用片段交易來切換片段中各個檢視區塊的顯示設定,但如果您想將顯示狀態變更為與返回堆疊中的交易有關聯,就很適合使用這些方法。

附加和卸離片段

FragmentTransaction 方法 detach() 會將片段從 UI 卸離,並刪除其檢視區塊階層。片段會繼續處於其在返回堆疊中的狀態 (STOPPED)。這表示片段雖然已從 UI 中移除,但仍是由片段管理員所管理。

attach() 方法會重新附加先前已卸離的片段。這會導致系統重新建立檢視區塊階層、將階層附加至 UI 並顯示該階層。

系統會將 FragmentTransaction 視為一組不可拆分的作業,因此如果在同一交易中針對相同片段例項同時呼叫 detachattach,兩者實際上會互相抵銷,避免系統刪除並立即重新建立片段的 UI。如要卸離並立即重新附加某個片段,請使用不同的交易並以 executePendingOperations() 分隔 (如有使用 commit())。