Xây dựng chế độ điều hướng thích ứng

Hầu hết ứng dụng đều có một vài đích đến cấp cao nhất có thể truy cập được thông qua giao diện người dùng điều hướng chính của ứng dụng. Trong các cửa sổ thu gọn, chẳng hạn như màn hình điện thoại chuẩn, đích đến thường hiển thị trong thanh điều hướng ở cuối cửa sổ. Trong cửa sổ mở rộng, chẳng hạn như ứng dụng toàn màn hình trên máy tính bảng, dải điều hướng dọc theo ứng dụng thường là lựa chọn phù hợp hơn vì các nút điều khiển điều hướng sẽ dễ tiếp cận hơn trong khi giữ bên trái và bên phải thiết bị.

NavigationSuiteScaffold đơn giản hoá việc chuyển đổi giữa các giao diện người dùng điều hướng bằng cách hiển thị thành phần kết hợp giao diện người dùng điều hướng thích hợp dựa trên WindowSizeClass. Điều này bao gồm việc tự động thay đổi giao diện người dùng trong quá trình thay đổi kích thước cửa sổ thời gian chạy. Hành vi mặc định là hiển thị một trong các thành phần giao diện người dùng sau:

  • Thanh điều hướng nếu chiều rộng hoặc chiều cao nhỏ gọn hoặc nếu thiết bị đang ở tư thế trên mặt bàn
  • Dải điều hướng cho mọi mục khác
Hình 1. NavigationSuiteScaffold hiển thị thanh điều hướng trong các cửa sổ thu gọn.
Hình 2. NavigationSuiteScaffold hiển thị dải điều hướng trong các cửa sổ mở rộng.

Thêm phần phụ thuộc

NavigationSuiteScaffold là một phần của thư viện Bộ điều hướng thích ứng Material3. Thêm phần phụ thuộc cho thư viện trong tệp build.gradle của ứng dụng hoặc mô-đun:

Kotlin


implementation("androidx.compose.material3:material3-adaptive-navigation-suite")

Groovy


implementation 'androidx.compose.material3:material3-adaptive-navigation-suite'

Tạo Scaffold

Hai phần chính của NavigationSuiteScaffold là các mục trong bộ điều hướng và nội dung cho đích đến đã chọn. Bạn có thể xác định trực tiếp các mục của bộ điều hướng trong một thành phần kết hợp, nhưng bạn nên xác định các mục này ở nơi khác, chẳng hạn như trong một enum:

enum class AppDestinations(
    @StringRes val label: Int,
    val icon: ImageVector,
    @StringRes val contentDescription: Int
) {
    HOME(R.string.home, Icons.Default.Home, R.string.home),
    FAVORITES(R.string.favorites, Icons.Default.Favorite, R.string.favorites),
    SHOPPING(R.string.shopping, Icons.Default.ShoppingCart, R.string.shopping),
    PROFILE(R.string.profile, Icons.Default.AccountBox, R.string.profile),
}

Để sử dụng NavigationSuiteScaffold, bạn phải theo dõi đích đến hiện tại bằng cách dùng rememberSaveable:

var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }

Trong ví dụ sau, tham số navigationSuiteItems (loại NavigationSuiteScope sử dụng hàm item để xác định giao diện người dùng điều hướng cho một đích đến riêng lẻ. Giao diện người dùng đích được sử dụng trên các thanh điều hướng, dải điều hướng và ngăn. Để tạo các mục điều hướng, bạn lặp lại AppDestinations của mình (được xác định trong đoạn mã trước):

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it }
            )
        }
    }
) {
    // TODO: Destination content.
}

Trong nội dung lambda đích đến, hãy sử dụng giá trị currentDestination để quyết định giao diện người dùng sẽ hiển thị. Nếu bạn dùng thư viện điều hướng trong ứng dụng của mình, hãy sử dụng thư viện đó tại đây để cho thấy đích đến thích hợp. Câu lệnh when có thể là đủ:

NavigationSuiteScaffold(
    navigationSuiteItems = { /*...*/ }
) {
    // Destination content.
    when (currentDestination) {
        AppDestinations.HOME -> HomeDestination()
        AppDestinations.FAVORITES -> FavoritesDestination()
        AppDestinations.SHOPPING -> ShoppingDestination()
        AppDestinations.PROFILE -> ProfileDestination()
    }
}

Thay đổi màu sắc

NavigationSuiteScaffold tạo một Surface trên toàn bộ khu vực mà Scaffold chiếm chỗ, thường là toàn bộ cửa sổ. Trên hết, Scaffold vẽ giao diện người dùng điều hướng cụ thể, chẳng hạn như NavigationBar. Cả nền tảng và giao diện người dùng điều hướng đều sử dụng các giá trị được chỉ định trong giao diện của ứng dụng, nhưng bạn có thể ghi đè các giá trị giao diện.

Tham số containerColor chỉ định màu của bề mặt. Mặc định là màu nền của bảng phối màu. Tham số contentColor chỉ định màu của nội dung trên khu vực đó. Giá trị mặc định là màu "bật" của bất kỳ màu nào được chỉ định cho containerColor. Ví dụ: nếu containerColor sử dụng màu background, thì contentColor sẽ sử dụng màu onBackground. Hãy xem phần Tuỳ chỉnh giao diện Material Design 3 trong Compose để biết thêm thông tin chi tiết về cách hoạt động của hệ thống màu. Khi ghi đè các giá trị này, hãy dùng các giá trị được xác định trong giao diện để ứng dụng hỗ trợ chế độ hiển thị tối và sáng:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    containerColor = MaterialTheme.colorScheme.primary,
    contentColor = MaterialTheme.colorScheme.onPrimary,
) {
    // Content...
}

Giao diện người dùng điều hướng được vẽ trước nền tảng NavigationSuiteScaffold. Các giá trị mặc định cho màu giao diện người dùng do NavigationSuiteDefaults.colors() cung cấp, nhưng bạn cũng có thể ghi đè các giá trị này. Ví dụ: nếu bạn muốn nền của thanh điều hướng rõ ràng nhưng các giá trị khác là giá trị mặc định, hãy ghi đè navigationBarContainerColor:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    navigationSuiteColors = NavigationSuiteDefaults.colors(
        navigationBarContainerColor = Color.Transparent,
    )
) {
    // Content...
}

Cuối cùng, bạn có thể tuỳ chỉnh từng mục trong giao diện người dùng điều hướng. Khi gọi hàm item, bạn có thể truyền một thực thể của NavigationSuiteItemColors. Lớp này sẽ chỉ định màu cho các mục trong thanh điều hướng, dải điều hướng và ngăn điều hướng. Tức là bạn có thể có các màu giống nhau trên từng loại giao diện người dùng điều hướng hoặc bạn có thể thay đổi màu sắc tuỳ theo nhu cầu của mình. Xác định màu ở cấp NavigationSuiteScaffold để sử dụng cùng một phiên bản đối tượng cho tất cả các mục và gọi hàm NavigationSuiteDefaults.itemColors() để chỉ ghi đè các màu mà bạn muốn thay đổi:

val myNavigationSuiteItemColors = NavigationSuiteDefaults.itemColors(
    navigationBarItemColors = NavigationBarItemDefaults.colors(
        indicatorColor = MaterialTheme.colorScheme.primaryContainer,
        selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer
    ),
)

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it },
                colors = myNavigationSuiteItemColors,
            )
        }
    },
) {
    // Content...
}

Tuỳ chỉnh các loại điều hướng

Hành vi mặc định của NavigationSuiteScaffold sẽ thay đổi giao diện người dùng điều hướng dựa trên các lớp kích thước cửa sổ. Tuy nhiên, bạn nên ghi đè hành vi này. Ví dụ: nếu ứng dụng của bạn hiển thị một ngăn nội dung lớn cho nguồn cấp dữ liệu, thì ứng dụng có thể dùng một ngăn điều hướng cố định cho cửa sổ mở rộng, nhưng vẫn quay lại hành vi mặc định cho các lớp có kích thước cửa sổ nhỏ gọn và trung bình:

val adaptiveInfo = currentWindowAdaptiveInfo()
val customNavSuiteType = with(adaptiveInfo) {
    if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    layoutType = customNavSuiteType,
) {
    // Content...
}

Tài nguyên khác

Xem hướng dẫn về Material Design:

Hãy xem các thành phần sau đây trong thư viện androidx.compose.material3: