導覽匣

「導覽匣」元件是滑入式選單,可讓使用者前往應用程式的各個部分。使用者可以從側邊滑動或輕觸選單圖示來啟用導覽匣。

請考慮實作 Navigation Drawer 的三種用途:

  • 內容分類:讓使用者在不同類別之間切換,例如在新聞或網誌應用程式中。
  • 帳戶管理:提供快速連結,可前往應用程式中的帳戶設定和個人資料部分,以便使用者帳戶使用者存取。
  • 功能探索:將多項功能和設定整理至單一選單,方便使用者在複雜的應用程式中進行探索及存取。

Material Design 提供兩種導覽匣:

  • 標準:與其他內容共用螢幕畫面。
  • 模式:會顯示在畫面中其他內容的上方。
圖 1. 導覽匣的範例。

範例

您可以使用 ModalNavigationDrawer 可組合項來實作導覽匣。

使用 drawerContent 位置提供 ModalDrawerSheet,並提供導覽匣的內容,如以下範例所示:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("Drawer title", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                label = { Text(text = "Drawer Item") },
                selected = false,
                onClick = { /*TODO*/ }
            )
            // ...other drawer items
        }
    }
) {
    // Screen content
}

ModalNavigationDrawer 可接受一些額外的導覽匣參數。舉例來說,您可以使用 gesturesEnabled 參數來切換導覽匣是否針對拖曳事件做出回應,如以下範例所示:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            // Drawer contents
        }
    },
    gesturesEnabled = false
) {
    // Screen content
}

控制行為

如要控制抽屜的開啟和關閉方式,請使用 DrawerState。您應使用 drawerState 參數將 DrawerState 傳遞至 ModalNavigationDrawer

DrawerState 提供 openclose 函式的存取權,以及與目前導覽匣狀態相關的屬性。這些暫停函式需要 CoroutineScope,您可以使用 rememberCoroutineScope 將其例項化。您也可以呼叫暫停函式,回應 UI 事件。

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        ModalDrawerSheet { /* Drawer content */ }
    },
) {
    Scaffold(
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Show drawer") },
                icon = { Icon(Icons.Filled.Add, contentDescription = "") },
                onClick = {
                    scope.launch {
                        drawerState.apply {
                            if (isClosed) open() else close()
                        }
                    }
                }
            )
        }
    ) { contentPadding ->
        // Screen content
    }
}

在導覽匣中建立群組

下列程式碼片段說明如何建立包含區段和分隔符的詳細導覽匣:

@Composable
fun DetailedDrawerExample(
    content: @Composable (PaddingValues) -> Unit
) {
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()

    ModalNavigationDrawer(
        drawerContent = {
            ModalDrawerSheet {
                Column(
                    modifier = Modifier.padding(horizontal = 16.dp)
                        .verticalScroll(rememberScrollState())
                ) {
                    Spacer(Modifier.height(12.dp))
                    Text("Drawer Title", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleLarge)
                    HorizontalDivider()

                    Text("Section 1", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Item 1") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Item 2") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )

                    HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))

                    Text("Section 2", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Settings") },
                        selected = false,
                        icon = { Icon(Icons.Outlined.Settings, contentDescription = null) },
                        badge = { Text("20") }, // Placeholder
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Help and feedback") },
                        selected = false,
                        icon = { Icon(Icons.AutoMirrored.Outlined.Help, contentDescription = null) },
                        onClick = { /* Handle click */ },
                    )
                    Spacer(Modifier.height(12.dp))
                }
            }
        },
        drawerState = drawerState
    ) {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = { Text("Navigation Drawer Example") },
                    navigationIcon = {
                        IconButton(onClick = {
                            scope.launch {
                                if (drawerState.isClosed) {
                                    drawerState.open()
                                } else {
                                    drawerState.close()
                                }
                            }
                        }) {
                            Icon(Icons.Default.Menu, contentDescription = "Menu")
                        }
                    }
                )
            }
        ) { innerPadding ->
            content(innerPadding)
        }
    }
}

程式碼的重點

  • 使用包含版面、分隔線和導覽項目的 Column 填入 drawerContent
  • ModalDrawerSheet 為導覽匣提供 Material Design 樣式。
  • HorizontalDivider 可用於分隔抽屜中的各個部分。
  • ModalNavigationDrawer 會建立抽屜。
  • drawerContent 定義抽屜的內容。
  • ModalDrawerSheet 中,Column 會垂直排列抽屜元素。
  • NavigationDrawerItem 可組合項代表抽屜中的個別項目。
  • Scaffold 提供畫面的基本結構,包括 TopAppBar
  • TopAppBar 中的 navigationIcon 會控制導覽匣的開啟和關閉狀態。

結果

下圖顯示開啟時的抽屜畫面,以及顯示的區段和項目:

詳細導覽匣,包含兩個部分,每個部分都有多個標有標籤的項目和圖示。
圖 2. 開啟的導覽匣,其中包含兩個巢狀群組。

其他資源