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 các 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 đó.
- Khả năng bố cục không ổn định: Điều này có thể gây ra sự cố nếu kích thước bố cục mẹ phụ thuộc vào kích thước của các thành phần con. Vì một thành phần con sử dụng
WindowInsetsRulers
có thể thay đổi vị trí hoặc kích thước trong quá trình đặt, nên thành phần này có thể tạo ra một chu kỳ bố cục không ổn định.
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.