對目的地套用邏輯或包裝函式

您可以使用 NavEntryDecorator 類別,為目的地提供額外資訊或套用相同邏輯。這個類別會使用可組合函式,將返回堆疊中的每個 NavEntry 納入。換句話說,它會「裝飾」項目的內容。

建立自訂裝飾器

如要建立裝飾器,請擴充 NavEntryDecorator 類別,並覆寫下列方法:

  • decorate:可組合 lambda,會針對返回堆疊中的每個 NavEntry 呼叫。它會接收 NavEntry 做為參數。這樣一來,您就能建立以項目 contentKey 為索引鍵的狀態物件。您可以使用 CompositionLocalProvider 為項目的內容提供依附元件。您也可以使用可組合函式包圍內容,或觸發附帶效果。請務必在這個方法中呼叫 entry.Content()。
  • onPop:當 NavEntry 從返回堆疊中移除並離開組合時,系統會叫用這個回呼。它會接收已移除項目的 contentKey。使用 contentKey 識別並清除與該項目相關聯的任何狀態。

以下範例會擴充 NavEntryDecorator 類別,建立自訂裝飾器。

// import androidx.navigation3.runtime.NavEntryDecorator
class CustomNavEntryDecorator<T : Any> : NavEntryDecorator<T>(
    decorate = { entry ->
        Log.d("CustomNavEntryDecorator", "entry with ${entry.contentKey} entered composition and was decorated")
        entry.Content()
    },
    onPop = { contentKey -> Log.d("CustomNavEntryDecorator", "entry with $contentKey was popped") }
)

如果裝飾器需要存取狀態,請建立可組合函式來建立該狀態,然後使用該狀態建構裝飾器。如需實作範例,請參閱 rememberSaveableStateHolderNavEntryDecorator 的原始碼。這會建立狀態 (SaveableStateHolder),並用來建構裝飾器。

裝飾返回堆疊

建立 NavEntryDecorator 後,請透過下列其中一種方式裝飾返回堆疊中的項目:

  • 使用 rememberDecoratedNavEntries。如果您有多個返回堆疊,且每個堆疊都有自己的修飾符組合,這個函式就非常實用 (詳情請參閱這份程式碼食譜)。這個函式會傳回 NavEntry 的裝飾清單,可與 NavDisplay 搭配使用。
  • 使用 entryDecorators 參數,直接將裝飾器提供給 NavDisplay。NavDisplay 會在幕後呼叫 rememberDecoratedNavEntries,並顯示裝飾過的項目。

加入預設裝飾器

Navigation 3 包含名為 SaveableStateHolderNavEntryDecorator 的預設裝飾器,可讓 NavEntry 的狀態在設定變更和程序終止後仍能保留。它會使用 SaveableStateProvider 包裝 NavEntry 內容,讓 NavEntry 內容中的 rememberSaveable 呼叫正常運作。

除非裝飾器提供 SaveableStateProvider,否則請在提供的裝飾器清單中,將 SaveableStateHolderNavEntryDecorator 做為第一個裝飾器。這個物件是使用 rememberSaveableStateHolderNavEntryDecorator 建立。

例如:

// import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
NavDisplay(
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        remember { CustomNavEntryDecorator() }
    ),
    // ...
)

使用 ResultEventBusNavEntryDecorator 傳遞結果

自 Navigation 3 1.2.0 起,您可以使用 ResultEventBusNavEntryDecorator,透過 LocalResultEventBus 組合本機為每個 NavEntry 提供 ResultEventBus。

根據預設,rememberResultEventBusNavEntryDecorator 會使用 rememberResultEventBus 在內部建立並記住自己的 ResultEventBus 執行個體。如需在裝飾器階層外 (例如頂層應用程式架構) 存取事件匯流排,可以呼叫 rememberResultEventBus 並傳遞至 rememberResultEventBusNavEntryDecorator(resultEventBus),藉此提升 ResultEventBus:

val resultEventBus = rememberResultEventBus()

NavDisplay(
    /* ... */
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        rememberResultEventBusNavEntryDecorator(resultEventBus = resultEventBus)
    )
)

如要進一步瞭解如何傳送及觀測結果,請參閱「傳回結果」。

修飾符的使用時機

裝飾器的用途如下:

  • 為返回堆疊中的每個 NavEntry 建立依附元件。舉例來說,ViewModelStoreNavEntryDecorator 會為每個 NavEntry 建立 ViewModelStore。
  • 在目的地之間傳遞結果及進行通訊。例如,ResultEventBusNavEntryDecorator 會為返回堆疊中的目的地提供 ResultEventBus。
  • 將物件範圍限定為多個NavEntry。例如,在多個項目之間共用 ViewModel。
  • 對多個NavEntry執行相同動作。例如,為每個項目執行記錄、偵錯或追蹤作業。
  • 使用相同的可組合函式納入 NavEntry。
  • 清除與 NavEntry 相關聯的狀態。舉例來說,從返回堆疊中移除項目時,ViewModelStoreNavEntryDecorator 會清除相關聯的 ViewModelStore。

請勿使用裝飾器執行下列操作:

  • 將依附元件傳遞至單一 NavEntry。
  • 提供範圍比返回堆疊更廣的依附元件。

在這兩種情況下,請改為在建立 NavEntry 時直接傳遞依附元件。

如需更多程式碼範例,請參閱 NavEntryDecorator。