WindowInsets
là API tiêu chuẩn trong Jetpack Compose để xử lý các vùng màn hình bị giao diện người dùng hệ thống che khuất một phần hoặc toàn bộ. Các vùng này bao gồm thanh trạng thái, thanh điều hướng và bàn phím ảo. Ngoài ra, bạn có thể truyền WindowInsetsRulers
được xác định trước như SafeDrawing
đến Modifier.fitInside
hoặc Modifier.fitOutside
để căn chỉnh nội dung với thanh hệ thống và vết cắt trên màn hình hoặc tạo WindowInsetsRulers
tuỳ chỉnh.
Ưu điểm của WindowInsetsRulers
- Tránh sự phức tạp khi sử dụng: Nó hoạt động trong giai đoạn đặt của bố cục. Điều này có nghĩa là nó hoàn toàn bỏ qua chuỗi sử dụng phần lồng ghép và luôn có thể cung cấp vị trí tuyệt đối, chính xác của các thanh hệ thống và vết cắt trên màn hình, bất kể bố cục mẹ đã thực hiện những gì. Việc sử dụng các phương thức
Modifier.fitInside
hoặcModifier.fitOutside
sẽ giúp ích trong việc khắc phục các vấn đề khi thành phần kết hợp tổ tiên tiêu thụ không chính xác các phần lồng ghép. - Dễ dàng tránh thanh hệ thống: Giúp nội dung ứng dụng của bạn tránh thanh hệ thống và vết cắt trên màn hình, đồng thời có thể đơn giản hơn so với việc sử dụng trực tiếp
WindowInsets
. - Có thể tuỳ chỉnh cao: Nhà phát triển có thể căn chỉnh nội dung theo các thước đo tuỳ chỉnh và kiểm soát chính xác bố cục bằng bố cục tuỳ chỉnh.
Nhược điểm của WindowInsetsRulers
- Không thể dùng cho hoạt động đo lường: Vì hoạt động này diễn ra trong giai đoạn đặt, nên thông tin vị trí mà hoạt động này cung cấp không có sẵn trong giai đoạn đo lường trước đó.
Điều chỉnh nội dung của bạn theo các phương thức Modifier
Modifier.fitInside
cho phép các ứng dụng căn chỉnh nội dung với thanh hệ thống và vết cắt trên màn hình. Bạn có thể dùng phương thức này thay cho WindowInsets
. Modifier.fitOutside
thường là nghịch đảo của Modifier.fitInside
.
Ví dụ: để xác minh rằng nội dung ứng dụng tránh thanh hệ thống và vết cắt trên màn hình, bạn có thể sử dụng fitInside(WindowInsetsRulers.safeDrawing.current)
.
@Composable fun FitInsideDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc... .fitInside(WindowInsetsRulers.SafeDrawing.current) ) }
Bảng sau đây cho biết nội dung ứng dụng của bạn sẽ trông như thế nào với các thước đo được xác định trước bằng Modifier.fitInside
hoặc Modifier.fitOutside
.
Loại thước kẻ được xác định trước | ||
---|---|---|
![]() |
![]() |
|
![]() |
Không áp dụng |
|
![]() |
![]() |
|
![]() |
Không áp dụng (thay vào đó, hãy dùng |
|
![]() |
![]() |
Để sử dụng Modifier.fitInside
và Modifier.fitOutside
, bạn phải hạn chế các thành phần kết hợp. Điều này có nghĩa là bạn phải xác định các đối tượng sửa đổi như Modifier.size
hoặc Modifier.fillMaxSize
.
Một số quy tắc như Modifier.fitOutside
trên SafeDrawing
và SystemBars
trả về nhiều quy tắc. Trong trường hợp này, Android sẽ đặt Thành phần kết hợp bằng một thước đo từ trái, trên cùng, phải, dưới cùng.
Tránh IME bằng Modifier.fitInside
Để xử lý các phần tử dưới cùng bằng IME có Modifier.fitInside
, hãy truyền vào một RectRuler
lấy giá trị trong cùng của NavigationBar
và Ime
.
@Composable fun FitInsideWithImeDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.NavigationBars.current, WindowInsetsRulers.Ime.current ) ) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier.align(Alignment.BottomStart).fillMaxWidth() ) } }
Tránh thanh trạng thái và thanh chú thích bằng Modifier.fitInside
Tương tự, để xác minh các phần tử trên cùng, hãy tránh thanh trạng thái và thanh chú thích cùng với Modifier.fitInsider
, truyền một RectRuler
lấy giá trị trong cùng của StatusBars
và CaptionBar
.
@Composable fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.StatusBars.current, WindowInsetsRulers.CaptionBar.current ) ) ) }
Tạo WindowInsetsRulers
tuỳ chỉnh
Bạn có thể căn chỉnh nội dung theo thước đo tuỳ chỉnh. Ví dụ: hãy xem xét trường hợp sử dụng trong đó một thành phần kết hợp mẹ xử lý không đúng phần lồng ghép, gây ra các vấn đề về khoảng đệm ở một thành phần con hạ lưu. Mặc dù có thể giải quyết vấn đề này bằng những cách khác, bao gồm cả việc sử dụng Modifier.fitInside
, bạn cũng có thể tạo một thước đo tuỳ chỉnh để căn chỉnh chính xác thành phần kết hợp con mà không cần phải khắc phục vấn đề ở thành phần kết hợp mẹ như trong ví dụ và video sau:
@Composable fun WindowInsetsRulersDemo(modifier: Modifier) { Box( contentAlignment = BottomCenter, modifier = modifier .fillMaxSize() // The mistake that causes issues downstream, as .padding doesn't consume insets. // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars), // assume it's difficult to identify this issue to see how WindowInsetsRulers can help. .padding(WindowInsets.navigationBars.asPaddingValues()) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child // Composable without having to fix the parent upstream. .alignToSafeDrawing() // .imePadding() // .fillMaxWidth() ) } } fun Modifier.alignToSafeDrawing(): Modifier { return layout { measurable, constraints -> if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right .current(0f).roundToInt() val left = WindowInsetsRulers.SafeDrawing.current.left .current(0f).roundToInt() measurable.measure(Constraints.fixed(right - left, height)) .place(left, bottom) } } else { val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
Video sau đây cho thấy ví dụ về việc sử dụng IME chèn có vấn đề do một thành phần mẹ ở phía trên trong hình ảnh bên trái và sử dụng các thước đo tuỳ chỉnh để khắc phục vấn đề ở bên phải. Khoảng đệm bổ sung xuất hiện bên dưới TextField
Composable vì khoảng đệm của thanh điều hướng không được thành phần mẹ sử dụng. Phần tử con được đặt ở đúng vị trí trong hình ảnh bên phải bằng cách sử dụng một thước đo tuỳ chỉnh như trong mẫu mã trước đó.
Xác minh rằng cha mẹ bị hạn chế
Để sử dụng WindowInsetsRulers
một cách an toàn, hãy đảm bảo rằng thành phần mẹ cung cấp các ràng buộc hợp lệ. Phần tử mẹ phải có kích thước xác định và không thể phụ thuộc vào kích thước của phần tử con sử dụng WindowInsetsRulers
. Sử dụng fillMaxSize
hoặc các đối tượng sửa đổi kích thước khác trên các thành phần kết hợp mẹ.
Tương tự, việc đặt một thành phần kết hợp sử dụng WindowInsetsRulers
bên trong một vùng chứa có thể cuộn như verticalScroll
có thể gây ra hành vi không mong muốn vì vùng chứa có thể cuộn cung cấp các ràng buộc chiều cao không giới hạn, không tương thích với logic của thước đo.