Đ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.

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 luikeys
. Bạn có thể sử dụngAny
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 đến và quay 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ộtNavEntry
có loại và nội dung kết hợp đã choentry
chấp nhận tham sốmetadata
để đặtNavEntry.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ộtList
có thể quan sát được, do đó, nó sẽ kích hoạt quy trình kết hợp lạiNavDisplay
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ượngNavEntry
. - 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:

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:

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.
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.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ấpNavEntry
được liên kết, chứa cả khoá và nội dung.Nội dung được hiển thị.
NavDisplay
nhậnNavEntry
và hiển thị nội dung.