Sau khi Hoạt động của bạn nắm quyền kiểm soát việc xử lý tất cả các phần lồng ghép, bạn có thể sử dụng API Compose để xác minh rằng nội dung không bị che khuất và các thành phần có thể tương tác không chồng chéo với giao diện người dùng hệ thống. Các API này cũng đồng bộ hoá bố cục của ứng dụng với các thay đổi về phần lồng ghép.
Xử lý phần lồng ghép bằng cách sử dụng khoảng đệm hoặc công cụ sửa đổi kích thước
Ví dụ: đây là phương thức cơ bản nhất để áp dụng các phần lồng ghép cho nội dung của toàn bộ ứng dụng:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { Box(Modifier.safeDrawingPadding()) { // the rest of the app } } }
Đoạn mã này áp dụng phần lồng ghép cửa sổ safeDrawing làm khoảng đệm xung quanh toàn bộ nội dung của ứng dụng. Mặc dù điều này đảm bảo rằng các thành phần có thể tương tác không chồng chéo với giao diện người dùng hệ thống, nhưng cũng có nghĩa là không có thành phần nào của ứng dụng sẽ vẽ phía sau giao diện người dùng hệ thống để đạt được hiệu ứng tràn viền. Để tận dụng tối đa toàn bộ cửa sổ, bạn cần tinh chỉnh vị trí áp dụng các phần lồng ghép trên cơ sở từng màn hình hoặc từng thành phần.
Tất cả các loại phần lồng ghép này đều được tạo ảnh động tự động bằng ảnh động IME được chuyển về API 21. Theo đó, tất cả bố cục sử dụng các phần lồng ghép này cũng tự động tạo ảnh động khi giá trị phần lồng ghép thay đổi.
Có 3 cách để xử lý khoảng lùi nhằm điều chỉnh bố cục composable:
Đối tượng sửa đổi khoảng đệm
Modifier.windowInsetsPadding(windowInsets: WindowInsets) áp dụng các phần lồng ghép cửa sổ đã cho làm khoảng đệm, hoạt động giống như Modifier.padding.
Ví dụ: Modifier.windowInsetsPadding(WindowInsets.safeDrawing) áp dụng các phần lồng ghép vẽ an toàn làm khoảng đệm ở cả 4 cạnh.
Ngoài ra, còn có một số phương thức tiện ích tích hợp sẵn cho các loại phần lồng ghép phổ biến nhất.
Modifier.safeDrawingPadding() là một phương thức như vậy, tương đương với Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Bảng sau đây liệt kê các đối tượng sửa đổi khoảng đệm tích hợp sẵn và loại WindowInsets mà mỗi đối tượng sửa đổi áp dụng:
Để biết nội dung của từng loại phần lồng ghép, hãy xem bài viết Giới thiệu về phần lồng ghép cửa sổ.
Đối tượng sửa đổi kích thước lồng ghép
Các đối tượng sửa đổi sau đây áp dụng một lượng phần lồng ghép cửa sổ bằng cách đặt kích thước của thành phần thành kích thước của phần lồng ghép:
Áp dụng cạnh bắt đầu của windowInsets làm chiều rộng (như |
|
Áp dụng cạnh cuối của windowInsets làm chiều rộng (như |
|
Áp dụng cạnh trên của windowInsets làm chiều cao (như |
|
|
Áp dụng cạnh dưới của windowInsets làm chiều cao (như |
Các đối tượng sửa đổi này đặc biệt hữu ích khi định cỡ một Spacer chiếm không gian của phần lồng ghép:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
Mức tiêu thụ phần lồng ghép
Đối tượng sửa đổi khoảng đệm lồng ghép (windowInsetsPadding và các trình trợ giúp như safeDrawingPadding) tự động sử dụng phần lồng ghép được áp dụng làm khoảng đệm. Khi đi sâu hơn vào cây thành phần, các đối tượng sửa đổi khoảng đệm lồng ghép và đối tượng sửa đổi kích thước lồng ghép biết rằng một số phần của phần lồng ghép đã được các đối tượng sửa đổi khoảng đệm lồng ghép bên ngoài sử dụng, đồng thời tránh sử dụng cùng một phần của phần lồng ghép nhiều lần, điều này sẽ dẫn đến quá nhiều không gian thừa.
Đối tượng sửa đổi kích thước phần lồng ghép cũng tránh sử dụng cùng một phần của phần lồng ghép nhiều lần nếu phần lồng ghép đã được sử dụng. Tuy nhiên, vì trực tiếp thay đổi kích thước nên các thành phần này không tự sử dụng phần lồng ghép.
Do đó, việc lồng các modifier khoảng đệm sẽ tự động thay đổi lượng khoảng đệm áp dụng cho mỗi composable.
Xem cùng một ví dụ về LazyColumn như trước, LazyColumn đang được đổi kích thước bằng đối tượng sửa đổi imePadding. Bên trong LazyColumn, mục cuối cùng có kích thước bằng chiều cao của phần dưới cùng của thanh hệ thống:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
Khi IME đóng, imePadding() sẽ không áp dụng khoảng đệm. Do đó, không có phần lồng ghép nào được sử dụng và chiều cao của Spacer khớp với thanh hệ thống dưới cùng.
Khi IME mở, các phần lồng ghép IME sẽ tạo ảnh động để khớp với kích thước của IME và đối tượng sửa đổi imePadding() bắt đầu áp dụng khoảng đệm dưới cùng để đổi kích thước LazyColumn khi IME mở. Khi đối tượng sửa đổi imePadding() bắt đầu áp dụng khoảng đệm dưới cùng, đối tượng này cũng bắt đầu sử dụng lượng phần lồng ghép đó. Do đó, chiều cao của Spacer bắt đầu giảm, vì một phần khoảng cách cho các thanh hệ thống đã được áp dụng bởi đối tượng sửa đổi imePadding(). Sau khi đối tượng sửa đổi imePadding() áp dụng một khoảng đệm dưới cùng lớn hơn các thanh hệ thống, chiều cao của Spacer sẽ bằng 0.
Khi IME đóng, các thay đổi sẽ diễn ra theo chiều ngược lại: Spacer mở rộng từ chiều cao bằng 0 khi imePadding() áp dụng ít hơn các thanh hệ thống dưới cùng.
Cuối cùng, chiều cao của Spacer khớp với các thanh hệ thống sau khi IME hoàn tất hiệu ứng động.
TextField.Hành vi này được thực hiện thông qua hoạt động giao tiếp giữa tất cả
các đối tượng sửa đổi windowInsetsPadding và có thể chịu ảnh hưởng theo một số
cách khác.
Modifier.consumeWindowInsets(insets: WindowInsets) cũng sử dụng các phần lồng ghép theo cách tương tự như Modifier.windowInsetsPadding, nhưng không áp dụng các phần lồng ghép đã sử dụng làm khoảng đệm. Điều này rất hữu ích khi kết hợp với đối tượng sửa đổi kích thước phần lồng ghép, để cho các thành phần đồng cấp biết rằng một lượng phần lồng ghép nhất định đã được sử dụng:
Column(Modifier.verticalScroll(rememberScrollState())) { Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars)) Column( Modifier.consumeWindowInsets( WindowInsets.systemBars.only(WindowInsetsSides.Vertical) ) ) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) } Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars)) }
Modifier.consumeWindowInsets(paddingValues: PaddingValues) hoạt động rất giống với phiên bản có đối số WindowInsets, nhưng lấy một PaddingValues tuỳ ý để sử dụng. Điều này rất hữu ích khi thông báo cho các thành phần con khi khoảng đệm hoặc khoảng cách được cung cấp bởi một số cơ chế khác ngoài đối tượng sửa đổi khoảng đệm lồng ghép, chẳng hạn như Modifier.padding thông thường hoặc khoảng cách có chiều cao cố định:
Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) }
Trong trường hợp cần có các phần lồng ghép cửa sổ thô mà không cần sử dụng, hãy dùng trực tiếp các giá trị WindowInsets hoặc dùng WindowInsets.asPaddingValues() để trả về PaddingValues của các phần lồng ghép không chịu ảnh hưởng của việc sử dụng.
Tuy nhiên, do những lưu ý sau, bạn nên sử dụng đối tượng sửa đổi khoảng đệm lồng ghép cửa sổ và đối tượng sửa đổi kích thước lồng ghép cửa sổ bất cứ khi nào có thể.
Các giai đoạn của Jetpack Compose và phần lồng ghép
Compose sử dụng các API cốt lõi AndroidX cơ bản để cập nhật và tạo ảnh động cho các phần lồng ghép, sử dụng các API nền tảng cơ bản quản lý các phần lồng ghép. Do hành vi đó của nền tảng, các phần lồng ghép có mối quan hệ đặc biệt với các giai đoạn của Jetpack Compose.
Giá trị của phần lồng ghép được cập nhật sau giai đoạn kết hợp, nhưng trước giai đoạn bố cục. Điều này có nghĩa là việc đọc giá trị của các phần lồng ghép trong thành phần kết hợp thường sử dụng giá trị của các phần lồng ghép bị trễ một khung hình. Các đối tượng sửa đổi tích hợp được mô tả trên trang này được xây dựng để trì hoãn việc sử dụng giá trị của các phần lồng ghép cho đến giai đoạn bố cục, nhằm đảm bảo rằng các giá trị lồng ghép được sử dụng trên cùng một khung hình khi chúng được cập nhật.