Điều hướng 3

Navigation 3 là một thư viện điều hướng được thiết kế từ đầu cho Jetpack Compose. Hướng dẫn này giải thích cách triển khai thành phần Điều hướng 3 trong các ứng dụng Wear OS.

Khái niệm cốt lõi

  • NavKey: Giá trị nhận dạng an toàn về kiểu, có thể chuyển đổi tuần tự cho một đích đến (màn hình) trong ứng dụng của bạn.
  • NavBackStack: Một danh sách có thể thay đổi gồm các thực thể NavKey đại diện cho nhật ký điều hướng. Bạn đẩy và lấy các mục trực tiếp từ danh sách này.
  • rememberNavBackStack: Một composable tạo và duy trì ngăn xếp lui khi có các thay đổi về cấu hình và quá trình bị buộc tắt.
  • NavDisplay: Thành phần giao diện người dùng cốt lõi theo dõi ngăn xếp lui và kết xuất màn hình đang hoạt động.
  • EntryProvider: Một DSL ánh xạ liên kết một NavKey với giao diện người dùng @Composable thực tế của nó.
  • SwipeDismissableSceneStrategy: Chiến lược dành riêng cho Wear, giúp bao bọc màn hình của bạn trong cử chỉ vuốt để đóng và xử lý các ảnh động quay lại tích hợp.

Bước 1: Thêm phần phụ thuộc

Thêm các phần phụ thuộc Navigation 3, Wear Compose và Serialization bắt buộc vào dự án của bạn.

Groovy

dependencies {
    // Core Navigation 3 APIs
    implementation "androidx.navigation3:navigation3-runtime:1.2.0-alpha02"
    implementation "androidx.navigation3:navigation3-ui:1.2.0-alpha02"

    // Wear OS specific Navigation 3 integration
    implementation "androidx.wear.compose:compose-navigation3:1.6.1"

    // Kotlinx Serialization for type-safe routing
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0"
}

Kotlin

dependencies {
    // Core Navigation 3 APIs
    implementation("androidx.navigation3:navigation3-runtime:1.2.0-alpha02")
    implementation("androidx.navigation3:navigation3-ui:1.2.0-alpha02")

    // Wear OS specific Navigation 3 integration
    implementation("androidx.wear.compose:compose-navigation3:1.6.1")

    // Kotlinx Serialization for type-safe routing
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0")
}

Bước 2: Xác định vị trí xuất hiện (NavKey)

Màn hình được xác định là các đối tượng hoặc lớp dữ liệu có thể chuyển đổi tuần tự và được nhập mạnh, triển khai giao diện NavKey.

@Serializable
sealed interface Screen : NavKey {
    @Serializable
    data object Home : Screen

    @Serializable
    data class Details(val itemId: String) : Screen
}

Bước 3: Thiết lập NavDisplay và ngăn xếp lui

Ở gốc của ứng dụng, hãy khởi động ngăn xếp lui và chiến lược cảnh Wear OS, sau đó cắm chúng vào NavDisplay.

// 1. Create the persistent back stack starting at the Home screen
val backStack = rememberNavBackStack(Screen.Home)

// 2. Initialize the Wear OS swipe-to-dismiss strategy
val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()

// 3. Render the NavDisplay
NavDisplay(
    backStack = backStack,
    sceneStrategies = listOf(strategy),
    entryProvider = entryProvider {
        // 4. Map keys to Composables
        entry<Screen.Home> {
            HomeScreen(
                onNavigateToDetails = { id -> backStack.add(Screen.Details(id)) }
            )
        }
        entry<Screen.Details> { key ->
            DetailsScreen(
                itemId = key.itemId,
                onBack = { backStack.removeAt(backStack.lastIndex) }
            )
        }
    }
)

Bước 4: Thực hiện các thao tác điều hướng

Vì ngăn xếp lui chỉ là một MutableList tuỳ chỉnh, nên thao tác điều hướng cực kỳ đơn giản. Bạn thực hiện các thao tác trực tiếp trên thực thể backStack:

  • Di chuyển về phía trước: backStack.add(Screen.Details("123"))
  • Quay lại: backStack.removeLast() hoặc backStack.removeLastOrNull()
  • Xoá và đặt lại: backStack.clear(); backStack.add(Screen.Home) (hoặc dùng các thao tác trên danh sách để thay thế ngăn xếp).

Bước 5: (Không bắt buộc) Xác định phạm vi của ViewModel cho các đích đến

Theo mặc định, ViewModel được giới hạn trong Activity. Navigation 3 cung cấp một cấu phần phần mềm cụ thể (lifecycle-viewmodel-navigation3) để phạm vi ViewModel một cách an toàn cho NavEntry trên ngăn xếp lui. Khi đích đến được đẩy ra khỏi ngăn xếp lui, ViewModel sẽ bị xoá.

  1. Thêm phần phụ thuộc:

    implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:...")
    
  2. Thêm trình trang trí kho lưu trữ ViewModel vào NavDisplay của entryDecorators. Bạn cũng phải đưa SaveableStateHolderNavEntryDecorator một cách rõ ràng khi cung cấp các đối tượng trang trí tuỳ chỉnh để giữ lại trạng thái rememberSaveable của Compose:

    NavDisplay(
        backStack = backStack,
        sceneStrategies = listOf(strategy),
        entryDecorators = listOf(
            rememberSaveableStateHolderNavEntryDecorator(),
            rememberViewModelStoreNavEntryDecorator()
        ),
        entryProvider = entryProvider {
            entry<Screen.Home> {
                // Any viewModel() requested here will be scoped to this NavEntry
                val viewModel: HomeViewModel = viewModel()
            }
        }
    )