Trình trang trí cảnh cho phép bạn sửa đổi cảnh do chiến lược cảnh của ứng dụng tính toán. Trên thực tế, các thành phần này được dùng cho giai đoạn thứ hai của việc tạo nội dung mà NavDisplay hiển thị.
Phương pháp này cho phép bạn đóng gói chức năng cụ thể (chẳng hạn như hiển thị các thành phần giao diện người dùng chung) vào từng đối tượng trang trí cảnh riêng lẻ.
Ví dụ: hãy xem xét một ứng dụng cải thiện hiệu suất có 3 tuyến cấp cao nhất: hộp thư đến, hộp thư đến của tin nhắn trực tiếp và chế độ xem lịch. Một ứng dụng như vậy có thể sử dụng hai thành phần trang trí cảnh, một để thêm thanh ứng dụng trên cùng hiển thị thông tin và các chế độ kiểm soát cho tuyến đường cấp cao nhất hiện tại và một để thêm thanh điều hướng hoặc dải điều hướng liên tục để di chuyển giữa các tuyến đường.
Tạo chiến lược trang trí cảnh
Trình trang trí cảnh tuân theo một mẫu tương tự như chiến lược cảnh. Để xác định một đối tượng trang trí cảnh, hãy triển khai giao diện SceneDecoratorStrategy. Giao diện này có một phương thức là decorateScene, tương tự như phương thức calculateScene của giao diện SceneStrategy.
decorateScene xác định xem có thể trang trí cảnh hay không:
- Nếu chiến lược trang trí cảnh của bạn không nên trang trí cảnh đầu vào, thì chiến lược này sẽ trả về cảnh đầu vào nguyên trạng.
- Nếu nên trang trí cảnh đầu vào, thì nó sẽ trả về một
Scenemới. Nhìn chung, cảnh được trả về sẽ lấy cảnh đầu vào làm tham số và gọi phương thứccontentcủa cảnh đầu vào trong phương thứccontentcủa chính cảnh đó.
Để xác định xem có nên trang trí cảnh đầu vào hay không và trang trí như thế nào, chiến lược trang trí cảnh có thể xem xét siêu dữ liệu của cả Scene đầu vào và các mục có trong cảnh đó.
class MySceneDecoratorStrategy<T : Any> : SceneDecoratorStrategy<T> { override fun SceneDecoratorStrategyScope<T>.decorateScene(scene: Scene<T>): Scene<T> { // `shouldDecorate` determines if the scene should be decorated based on scene.metadata, // scene.entries.metadata, or any other relevant state. return if (shouldDecorate(scene)) { MyDecoratingScene(scene) } else { scene } } } class MyDecoratingScene<T : Any>(scene: Scene<T>) : Scene<T> { // ... override val content = @Composable { scene.content() } }
Sử dụng các chiến lược trang trí cảnh
Để sử dụng các chiến lược trang trí cảnh, hãy cung cấp các chiến lược đó cho NavDisplay bằng cách sử dụng tham số sceneDecoratorStrategies. Khi trang trí các cảnh, NavDisplay sẽ gọi phương thức decorateScene của từng chiến lược theo trình tự, truyền đầu ra của mỗi lệnh gọi làm đầu vào cho lệnh gọi tiếp theo.
NavDisplay( // ... sceneDecoratorStrategies = listOf(firstSceneDecoratorStrategy, secondSceneDecoratorStrategy) )
Các mẫu phổ biến cho đối tượng trang trí cảnh
Khi triển khai trình trang trí cảnh, bạn cần lưu ý một số mẫu phổ biến sau:
Sao chép thuộc tính
Trong nhiều trường hợp, cảnh do việc trang trí một cảnh trả về phải chứa các mục giống nhau và có các mục trước đó giống như cảnh mà cảnh đó đang trang trí. Ngoài ra, có thể nó sẽ kế thừa (hoặc sửa đổi) siêu dữ liệu của cảnh mà nó đang trang trí, thay vì sử dụng hành vi mặc định. Đoạn mã sau đây minh hoạ một ví dụ về cách thực hiện việc này:
class CopyingScene<T : Any>(scene: Scene<T>) : Scene<T> { override val entries = scene.entries override val previousEntries = scene.previousEntries override val metadata = scene.metadata // ... }
Duy trì ảnh động
Như được trình bày chi tiết trong phần Tạo hiệu ứng động giữa các đích đến, NavDisplay sẽ tự động tạo hiệu ứng động cho các quá trình chuyển đổi giữa các cảnh khi một khoá bắt nguồn từ lớp của cảnh hiện tại và thuộc tính key của cảnh đó thay đổi.
Khi bạn giới thiệu các thành phần trang trí cảnh cho ứng dụng, lớp cảnh được trả về sau khi trang trí cảnh có thể vẫn giữ nguyên, ngay cả khi lớp cảnh được trả về trong quá trình tính toán cảnh thay đổi. Khi điều này xảy ra và các cảnh trang trí sao chép trực tiếp key của cảnh mà chúng đang trang trí, thì các ảnh động tích hợp sẽ không còn xảy ra nữa vì khoá phái sinh không thay đổi.
Để duy trì tính năng hỗ trợ ảnh động tích hợp sẵn, các cảnh trang trí phải sử dụng một khoá bắt nguồn từ lớp và key của cảnh do calculateScene trả về.
class DerivedKeyScene<T : Any>(scene: Scene<T>) : Scene<T> { override val key = scene::class to scene.key // ... }