瞭解並實作基本概念

導覽是指使用者在應用程式中移動的方式。使用者通常會輕觸或點選 UI 元素進行互動,應用程式則會回應並顯示新內容。如果使用者想返回先前的內容,可以使用返回手勢或輕觸返回按鈕。

模擬導覽狀態

使用內容堆疊是模擬這類行為的方便方法。當使用者向前瀏覽新內容時,系統會將該內容推送至堆疊頂端。當使用者從該內容「返回」時,系統會將該內容彈出堆疊,並顯示先前的內容。在導覽用語中,這個堆疊通常稱為「返回堆疊」,因為它代表使用者「可以返回」的內容。

軟體鍵盤動作按鈕 (勾號圖示),以紅色圓圈標示。
圖 1. 圖表顯示返回堆疊如何隨著使用者瀏覽事件而變更。

建立返回堆疊

在 Navigation 3 中,返回堆疊實際上不含任何內容。而是包含內容參照,也就是所謂的。鍵可以是任何類型,但通常是簡單的序列化資料類別。使用參照而非內容有以下優點:

  • 只要將按鍵推送至返回堆疊,即可輕鬆瀏覽。
  • 只要鍵可序列化,返回堆疊就能儲存至永久性儲存空間,讓返回堆疊在設定變更和程序終止後繼續留存。這一點很重要,因為使用者預期可以離開應用程式,稍後再回來,並在相同的內容顯示畫面中繼續瀏覽。詳情請參閱「儲存返回堆疊」一文。

Navigation 3 API 中的重要概念是您擁有後置堆疊。程式庫:

  • 預期返回堆疊會是快照狀態備份的 List<T>,其中 T 是返回堆疊 keys 的類型。您可以使用 Any,也可以提供更強型別的鍵。當您看到「push」或「pop」時,底層實作方式是在清單結尾處新增或移除項目。
  • 觀察返回堆疊,並使用 NavDisplay 在 UI 中反映其狀態。

以下範例說明如何建立鍵和返回堆疊,並修改返回堆疊以回應使用者導覽事件:

// Define keys that will identify content
data object ProductList
data class ProductDetail(val id: String)

@Composable
fun MyApp() {

    // Create a back stack, specifying the key the app should start with
    val backStack = remember { mutableStateListOf<Any>(ProductList) }

    // Supply your back stack to a NavDisplay so it can reflect changes in the UI
    // ...more on this below...

    // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state
    backStack.add(ProductDetail(id = "ABC"))

    // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state
    backStack.removeLastOrNull()
}

將鍵解析為內容

在 Navigation 3 中,使用 NavEntry 模擬內容,這是包含可組合函式的類別。代表目的地:使用者可以前往返回的單一內容。

NavEntry 也可能包含中繼資料,也就是內容相關資訊。容器物件 (例如 NavDisplay) 可以讀取這類中繼資料,藉此決定如何顯示 NavEntry 的內容。舉例來說,您可以使用中繼資料覆寫特定 NavEntry 的預設動畫。NavEntry metadataString 鍵與 Any 值的對應,可提供多樣化的資料儲存空間。

如要將 key 轉換為 NavEntry,請建立 entryProvider。這個函式會接受 key,並傳回該 keyNavEntry。在建立 NavDisplay 時,通常會將其定義為 lambda 參數。

建立 entryProvider 的方式有兩種,您可以直接建立 lambda 函式,也可以使用 entryProvider DSL。

直接建立 entryProvider 函式

您通常會使用 when 陳述式建立 entryProvider 函式,並為每個鍵建立分支。

entryProvider = { key ->
    when (key) {
        is ProductList -> NavEntry(key) { Text("Product List") }
        is ProductDetail -> NavEntry(
            key,
            metadata = mapOf("extraDataKey" to "extraDataValue")
        ) { Text("Product ${key.id} ") }

        else -> {
            NavEntry(Unit) { Text(text = "Invalid Key: $it") }
        }
    }
}

使用 entryProvider DSL

entryProvider DSL 可避免您需要針對每個鍵類型進行測試,並為每個鍵類型建構 NavEntry,藉此簡化 lambda 函式。請使用 entryProvider 建構函式。如果找不到索引鍵,也會包含預設的備用行為 (擲回錯誤)。

entryProvider = entryProvider {
    entry<ProductList> { Text("Product List") }
    entry<ProductDetail>(
        metadata = mapOf("extraDataKey" to "extraDataValue")
    ) { key -> Text("Product ${key.id} ") }
}

請注意程式碼片段中的以下事項:

  • entry 可用於定義具有指定類型和可組合內容的 NavEntry
  • entry 會接受 metadata 參數,用於設定 NavEntry.metadata

顯示返回堆疊

返回堆疊代表應用程式的導覽狀態。只要返回堆疊發生變更,應用程式 UI 就應反映新的返回堆疊狀態。在 Navigation 3 中,NavDisplay 會觀察返回堆疊,並據此更新 UI。請使用下列參數建構:

  • 返回堆疊 - 應為 SnapshotStateList<T> 類型,其中 T 是返回堆疊鍵的類型。這是可觀察的 List,因此會在變更時觸發 NavDisplay 的重組作業。
  • entryProvider,用於將返回堆疊中的鍵轉換為 NavEntry
  • 您可以選擇為 onBack 參數提供 lambda。當使用者觸發返回事件時,系統會呼叫此方法。

以下範例說明如何建立 NavDisplay

data object Home
data class Product(val id: String)

@Composable
fun NavExample() {

    val backStack = remember { mutableStateListOf<Any>(Home) }

    NavDisplay(
        backStack = backStack,
        onBack = { backStack.removeLastOrNull() },
        entryProvider = { key ->
            when (key) {
                is Home -> NavEntry(key) {
                    ContentGreen("Welcome to Nav3") {
                        Button(onClick = {
                            backStack.add(Product("123"))
                        }) {
                            Text("Click to navigate")
                        }
                    }
                }

                is Product -> NavEntry(key) {
                    ContentBlue("Product ${key.id} ")
                }

                else -> NavEntry(Unit) { Text("Unknown route") }
            }
        }
    )
}

根據預設,NavDisplay 會在單一窗格版面配置中顯示後置堆疊上最頂層的 NavEntry。以下錄影畫面顯示此應用程式執行情形:

含有兩個目的地的 `NavDisplay` 預設行為。
圖 2. NavDisplay 具有兩個目的地的預設行為。

平台比一比

下圖顯示 Navigation 3 中各個物件之間的資料流動方式:

這張圖表顯示 Navigation 3 中各個物件之間的資料流動情形。
圖 3. 圖表顯示 Navigation 3 中資料如何流經各種物件。
  1. 導覽事件會啟動變更。系統會根據使用者互動內容,在返回堆疊中新增或移除鍵。

  2. 返回堆疊狀態變更會觸發內容擷取作業NavDisplay (用於轉譯返回堆疊的可組合函式) 會觀察返回堆疊。在預設設定中,它會在單一窗格版面配置中顯示最頂層的返回堆疊項目。當返回堆疊的頂端鍵變更時,NavDisplay 會使用這個鍵向輸入供應器要求對應的內容。

  3. 供應者提供內容。項目提供者是將索引鍵解析為 NavEntry 的函式。接收 NavDisplay 提供的金鑰後,輸入提供者會提供相關聯的 NavEntry,其中包含金鑰和內容。

  4. 顯示內容NavDisplay 會接收 NavEntry 並顯示內容。