清單詳細資料是一種 UI 模式,由雙窗格版面配置組成,其中一個窗格會顯示項目清單,另一個窗格則會顯示從清單中選取的項目詳細資料。
如果應用程式提供大量集合元素的深入資訊,這個模式就特別實用,例如電子郵件用戶端,其中包含電子郵件清單和每封電子郵件訊息的詳細內容。清單詳細資料也可用於較不重要的路徑,例如將應用程式偏好設定分成類別清單,並在詳細資料窗格中顯示各類別的偏好設定。

使用 NavigableListDetailPaneScaffold 實作清單/詳細資料模式
NavigableListDetailPaneScaffold 是可組合函式,可簡化在 Jetpack Compose 中實作清單詳細資料版面配置的程序。它會包裝 ListDetailPaneScaffold,並新增內建導覽和預測返回動畫。
清單詳細資料 Scaffold 最多支援三個窗格:
- 清單窗格:顯示項目集合。
- 詳細資料窗格:顯示所選項目的詳細資料。
- 額外窗格 (選用):視需要提供額外背景資訊。
Scaffold 會根據視窗大小調整:
- 在大型視窗中,清單和詳細資料窗格會並排顯示。
- 在小型視窗中,一次只能看到一個窗格,並隨著使用者瀏覽而切換。
宣告依附元件
NavigableListDetailPaneScaffold 是 Material 3 自動調整導覽程式庫的一部分。
在應用程式或模組的 build.gradle 檔案中,新增下列三個相關依附元件:
Kotlin
implementation("androidx.compose.material3.adaptive:adaptive") implementation("androidx.compose.material3.adaptive:adaptive-layout") implementation("androidx.compose.material3.adaptive:adaptive-navigation")
Groovy
implementation 'androidx.compose.material3.adaptive:adaptive' implementation 'androidx.compose.material3.adaptive:adaptive-layout' implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
- adaptive:低階建構區塊,例如
HingeInfo和Posture - adaptive-layout:自動調整版面配置,例如
ListDetailPaneScaffold和SupportingPaneScaffold - adaptive-navigation:用於在窗格內和窗格之間導覽的可組合項,以及預設支援導覽的自動調整式版面配置,例如
NavigableListDetailPaneScaffold和NavigableSupportingPaneScaffold
確認專案包含 compose-material3-adaptive 1.1.0-beta1 以上版本。
選擇啟用預測返回手勢
如要在 Android 15 以下版本啟用預測返回動畫,必須選擇加入預測返回手勢支援功能。如要選擇加入,請在 AndroidManifest.xml 檔案中,將 android:enableOnBackInvokedCallback="true" 新增至 <application> 標記或個別 <activity> 標記。詳情請參閱「選擇加入預測返回手勢」。
如果應用程式指定 Android 16 (API 級別 36) 以上版本為目標,系統會預設啟用預測返回手勢。
基本用法
按照下列方式實作 NavigableListDetailPaneScaffold:
- 使用代表所選內容的類別。使用
Parcelable類別,支援儲存及還原所選清單項目。使用 kotlin-parcelize 外掛程式為您產生程式碼。 - 使用
rememberListDetailPaneScaffoldNavigator建立ThreePaneScaffoldNavigator。
這個導覽器用於在清單、詳細資料和額外窗格之間移動。透過宣告泛型類型,導覽器也會追蹤 Scaffold 的狀態 (即顯示哪個 MyItem)。由於這個類型可封裝,因此導覽器可以儲存及還原狀態,自動處理設定變更。
將導覽器傳遞至
NavigableListDetailPaneScaffold可組合函式。將清單窗格實作提供給
NavigableListDetailPaneScaffold。使用AnimatedPane在導覽期間套用預設窗格動畫。然後使用ThreePaneScaffoldNavigator前往詳細資料窗格ListDetailPaneScaffoldRole.Detail,並顯示傳遞的項目。在
NavigableListDetailPaneScaffold中加入詳細資料窗格實作。
導覽完成後,currentDestination 會包含應用程式導覽至的窗格,包括窗格中顯示的內容。contentKey 屬性與原始呼叫中指定的類型相同,因此您可以存取任何需要顯示的資料。
- 您也可以視需要變更
NavigableListDetailPaneScaffold中的defaultBackBehavior。根據預設,NavigableListDetailPaneScaffold會使用PopUntilScaffoldValueChange進行defaultBackBehavior。
如果應用程式需要不同的返回瀏覽模式,您可以指定其他 BackNavigationBehavior 選項,覆寫這項行為。
BackNavigationBehavior 種付款方式
以下章節以電子郵件應用程式為例,其中一個窗格顯示電子郵件清單,另一個窗格則顯示詳細檢視畫面。
PopUntilScaffoldValueChange (預設,在多數情況下建議使用)
這項行為著重於整體版面配置結構的變更。在多窗格設定中,變更詳細資料窗格中的電子郵件內容不會改變基礎版面配置結構。因此,返回按鈕可能會退出應用程式或目前的導覽圖,因為在目前的情境中,沒有可還原的版面配置變更。在單一窗格版面配置中,按下返回鍵會略過詳細資料檢視畫面中的內容變更,並返回清單檢視畫面,因為這代表版面配置有明顯變更。
請見以下範例:
- 多窗格:您正在詳細資料窗格中查看電子郵件 (項目 1)。點選另一封電子郵件 (項目 2) 時,詳細資料窗格會更新,但清單和詳細資料窗格仍會顯示。按下返回鍵可能會退出應用程式或目前的導覽流程。
- 單一窗格:您先查看項目 1,再查看項目 2,按下返回鍵後,系統會直接將您帶回電子郵件清單窗格。
如果希望使用者在每次返回操作時,都能看到明顯的版面配置轉換,請使用這個選項。
PopUntilContentChange
這種行為會優先顯示內容。如果您先查看項目 1,再查看項目 2,無論版面配置為何,按下返回鍵都會回到項目 1。
請見以下範例:
- 多窗格:您在詳細資料窗格中查看項目 1,然後點選清單中的項目 2。詳細資料窗格會隨之更新。按下返回鍵會將詳細資料窗格還原為項目 1。
- 單一窗格:內容會還原成相同狀態。
如果使用者預期透過返回動作回到先前查看的內容,請使用這個選項。
PopUntilCurrentDestinationChange
這項行為會彈出返回堆疊,直到目前導覽目的地變更為止。這項原則同樣適用於單窗格和多窗格版面配置。
請見以下範例:
無論您是在單一或多窗格版面配置中,按下返回鍵一律會將焦點從醒目顯示的導覽元素移至上一個目的地。在電子郵件應用程式中,這表示所選窗格的視覺指示會轉移。
如果使用者體驗需要清楚顯示目前的導覽位置,請使用這個選項。
PopLatest
這個選項只會從返回堆疊中移除最近的目的地。如要返回瀏覽,而不略過中間狀態,請使用這個選項。
完成這些步驟後,您的程式碼應如下所示:
NavigableListDetailPaneScaffold( navigator = navigator, listPane = { AnimatedPane { ListContent( words = sampleWords, selectionState = navigator.currentDestination?.contentKey?.let { SelectionVisibilityState.ShowSelection(it) } ?: SelectionVisibilityState.NoSelection, onWordClick = { word -> scope.launch { navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word) } }, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout ) } }, detailPane = { AnimatedPane { DetailContent( definedWord = navigator.currentDestination?.contentKey, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout, onClosePane = { scope.launch { navigator.navigateBack( backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange ) } } ) } }