Tìm hiểu và triển khai các kiến thức cơ bản

Điều hướng mô tả cách người dùng thao tác trong ứng dụng của bạn. Người dùng tương tác với các phần tử trên giao diện người dùng, thường là bằng cách nhấn hoặc nhấp vào các phần tử đó và ứng dụng sẽ phản hồi bằng cách hiển thị nội dung mới. Nếu muốn quay lại nội dung trước, người dùng sẽ sử dụng cử chỉ quay lại hoặc nhấn vào nút quay lại.

Mô hình hoá trạng thái điều hướng

Một cách thuận tiện để mô hình hoá hành vi này là sử dụng một ngăn xếp nội dung. Khi người dùng điều hướng tiến đến nội dung mới, nội dung đó sẽ được đẩy lên đầu ngăn xếp. Khi người dùng nhấn nút quay lại từ nội dung đó, nội dung sẽ bị loại bỏ khỏi ngăn xếp và nội dung trước đó sẽ xuất hiện. Theo thuật ngữ điều hướng, ngăn xếp này thường được gọi là ngăn xếp lui vì nó đại diện cho nội dung mà người dùng có thể quay lại.

Nút hành động trên bàn phím phần mềm (biểu tượng dấu kiểm) được khoanh tròn màu đỏ.
Hình 1. Sơ đồ cho thấy cách ngăn xếp quay lại thay đổi theo các sự kiện điều hướng của người dùng.

Tạo ngăn xếp quay lại

Trong Navigation 3, ngăn xếp lui thực sự không chứa nội dung. Thay vào đó, tệp này chứa thông tin tham chiếu đến nội dung, còn được gọi là khoá. Khoá có thể thuộc bất kỳ loại nào nhưng thường là các lớp dữ liệu đơn giản, có thể chuyển đổi tuần tự. Việc sử dụng tệp tham chiếu thay vì nội dung mang lại những lợi ích sau:

  • Bạn có thể dễ dàng di chuyển bằng cách đẩy các khoá vào ngăn xếp lui.
  • Miễn là các khoá có thể được chuyển đổi tuần tự, ngăn xếp lui có thể được lưu vào bộ nhớ liên tục, cho phép ngăn xếp này duy trì các thay đổi về cấu hình và quá trình kết thúc. Điều này rất quan trọng vì người dùng mong muốn rời khỏi ứng dụng của bạn, quay lại ứng dụng sau và tiếp tục xem nội dung đang hiển thị từ thời điểm họ rời đi. Hãy xem phần Lưu ngăn xếp lui để biết thêm thông tin.

Một khái niệm chính trong Navigation 3 API là bạn sở hữu ngăn xếp lui. Thư viện:

  • Dự kiến ngăn xếp lui của bạn sẽ là List<T> được hỗ trợ bằng trạng thái ảnh chụp nhanh, trong đó T là loại ngăn xếp lui keys. Bạn có thể sử dụng Any hoặc cung cấp các khoá được nhập mạnh hơn của riêng mình. Khi bạn thấy các thuật ngữ "push" hoặc "pop", việc triển khai cơ bản là thêm hoặc xoá các mục khỏi cuối danh sách.
  • Theo dõi ngăn xếp quay lại và phản ánh trạng thái của ngăn xếp đó trong giao diện người dùng bằng NavDisplay.

Ví dụ sau đây cho thấy cách tạo các khoá và ngăn xếp quay lại, đồng thời sửa đổi ngăn xếp quay lại để phản hồi các sự kiện điều hướng của người dùng:

// 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()
}

Giải quyết các khoá cho nội dung

Nội dung được mô hình hoá trong Navigation 3 bằng NavEntry, đây là một lớp chứa hàm có khả năng kết hợp. Đây là đích đến – một phần nội dung mà người dùng có thể di chuyển đếnquay lại.

NavEntry cũng có thể chứa siêu dữ liệu – thông tin về nội dung. Các đối tượng vùng chứa (chẳng hạn như NavDisplay) có thể đọc siêu dữ liệu này để giúp chúng quyết định cách hiển thị nội dung của NavEntry. Ví dụ: siêu dữ liệu có thể được dùng để ghi đè các hiệu ứng chuyển động mặc định cho một NavEntry cụ thể. NavEntry metadata là một bản đồ gồm các khoá String đến các giá trị Any, cung cấp khả năng lưu trữ dữ liệu linh hoạt.

Để chuyển đổi key thành NavEntry, hãy tạo một Trình cung cấp mục nhập. Đây là một hàm chấp nhận key và trả về NavEntry cho key đó. Thường được xác định là một tham số lambda khi tạo NavDisplay.

Có 2 cách để tạo Trình cung cấp mục nhập, đó là tạo trực tiếp một hàm lambda hoặc sử dụng DSL entryProvider.

Tạo trực tiếp một hàm Trình cung cấp mục nhập

Thông thường, bạn sẽ tạo một hàm Entry Provider bằng câu lệnh when, với một nhánh cho mỗi khoá.

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") }
        }
    }
}

Sử dụng DSL entryProvider

DSL entryProvider có thể đơn giản hoá hàm lambda của bạn bằng cách tránh nhu cầu kiểm thử đối với từng loại khoá và tạo một NavEntry cho từng loại khoá. Hãy dùng hàm tạo entryProvider cho việc này. Thao tác này cũng bao gồm hành vi dự phòng mặc định (gây ra lỗi) nếu không tìm thấy khoá.

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

Xin lưu ý những điều sau trong đoạn mã:

  • entry dùng để xác định một NavEntry có loại và nội dung kết hợp đã cho
  • entry chấp nhận tham số metadata để đặt NavEntry.metadata

Hiển thị ngăn xếp lui

Ngăn xếp lui thể hiện trạng thái điều hướng của ứng dụng. Bất cứ khi nào ngăn xếp lui thay đổi, giao diện người dùng của ứng dụng sẽ phản ánh trạng thái mới của ngăn xếp lui. Trong Navigation 3, NavDisplay sẽ theo dõi ngăn xếp lui của bạn và cập nhật giao diện người dùng cho phù hợp. Tạo đối tượng này bằng các tham số sau:

  • Ngăn xếp sau – ngăn xếp này phải thuộc loại SnapshotStateList<T>, trong đó T là loại khoá ngăn xếp sau. Đây là một List có thể quan sát được, do đó, nó sẽ kích hoạt quy trình kết hợp lại NavDisplay khi thay đổi.
  • Một entryProvider để chuyển đổi các khoá trong ngăn xếp quay lại thành các đối tượng NavEntry.
  • Bạn có thể cung cấp một hàm lambda cho tham số onBack (không bắt buộc). Phương thức này được gọi khi người dùng kích hoạt một sự kiện quay lại.

Ví dụ sau đây cho thấy cách tạo 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") }
            }
        }
    )
}

Theo mặc định, NavDisplay sẽ cho thấy NavEntry trên cùng trong ngăn xếp sau ở bố cục một ngăn. Bản ghi sau đây cho thấy ứng dụng này đang chạy:

Hành vi mặc định của `NavDisplay` với 2 đích đến.
Hình 2. Hành vi mặc định của NavDisplay với 2 đích đến.

Kết hợp kiến thức đã học

Sơ đồ sau đây cho thấy cách dữ liệu di chuyển giữa các đối tượng trong Navigation 3:

Hình ảnh minh hoạ cách dữ liệu luân chuyển giữa các đối tượng trong Navigation 3.
Hình 3. Sơ đồ cho thấy cách dữ liệu truyền qua nhiều đối tượng trong Navigation 3.
  1. Sự kiện điều hướng bắt đầu các thay đổi. Các khoá được thêm hoặc xoá khỏi ngăn xếp lui để phản hồi các lượt tương tác của người dùng.

  2. Thay đổi trạng thái ngăn xếp lui sẽ kích hoạt quá trình truy xuất nội dung. NavDisplay (một thành phần kết hợp hiển thị ngăn xếp lui) theo dõi ngăn xếp lui. Trong cấu hình mặc định, thành phần này sẽ hiển thị mục nhập ngăn xếp lui trên cùng trong bố cục một ngăn. Khi khoá trên cùng trong ngăn xếp lui thay đổi, NavDisplay sẽ dùng khoá này để yêu cầu nội dung tương ứng từ nhà cung cấp mục nhập.

  3. Nhà cung cấp mục cung cấp nội dung. Trình cung cấp mục nhập là một hàm phân giải khoá thành NavEntry. Sau khi nhận được một khoá từ NavDisplay, trình cung cấp mục nhập sẽ cung cấp NavEntry được liên kết, chứa cả khoá và nội dung.

  4. Nội dung được hiển thị. NavDisplay nhận NavEntry và hiển thị nội dung.