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 hoàn toàn. Các khu vực 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 độ phức tạp khi sử dụng: Hàm này hoạt động trong giai đoạn đặt 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í chính xác, tuyệt đối 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ẹ đã làm gì. Việc sử dụng phương thức
Modifier.fitInsidehoặcModifier.fitOutsidesẽ giúp khắc phục các vấn đề khi thành phần kết hợp cấp trên sử dụng các phần lồng ghép không chính xác. - Dễ dàng tránh các thanh hệ thống: Thành phần này giúp nội dung ứng dụng của bạn tránh các 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. - Khả năng tuỳ chỉnh cao: Nhà phát triển có thể căn chỉnh nội dung theo thước 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 để đo lường: Vì hoạt động trong giai đoạn đặt, nên thông tin vị trí mà thuộc tính này cung cấp không có sẵn trong giai đoạn đo lường trước đó.
Căn chỉnh nội dung bằng các phương thức của đối tượng sửa đổi
Modifier.fitInside cho phép các ứng dụng căn chỉnh nội dung theo thanh hệ thống và vết cắt trên màn hình. Bạn có thể sử dụng thuộc tính 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 các 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 thấy nội dung ứng dụng của bạn sẽ trông như thế nào với các thước kẻ được xác định trước bằng Modifier.fitInside hoặc Modifier.fitOutside.
| Loại thước được xác định trước | ||
|---|---|---|
![]() |
![]() |
|
![]() |
Không áp dụng |
|
![]() |
![]() |
|
![]() |
Không áp dụng (thay vào đó, hãy sử dụng |
|
![]() |
![]() |
Để sử dụng Modifier.fitInside và Modifier.fitOutside, bạn cần ràng buộc 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ố thước đo như Modifier.fitOutside trên SafeDrawing và SystemBars trả về nhiều thước đo. Trong trường hợp này, Android đặt Thành phần kết hợp bằng một thước kẻ từ trái, trên, phải, dưới.
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 tránh thanh trạng thái và thanh chú thích cùng với Modifier.fitInside, hãy 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 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 cách các phần lồng ghép, gây ra vấn đề về khoảng đệm trong một thành phần kết hợp con hạ nguồn. Mặc dù vấn đề này có thể được giải quyết theo những cách khác, bao gồm cả việc sử dụng Modifier.fitInside, nhưng 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 composable con mà không cần phải khắc phục vấn đề trong thành phần composable mẹ ngược dòng 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 phần lồng ghép IME có vấn đề do thành phần mẹ ngược dòng gây ra trong hình ảnh bên trái và cách sử dụng thước 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 thành phần composable TextField vì khoảng đệm của thanh điều hướng không được thành phần mẹ sử dụng. Thành phần con được đặt ở vị trí chính xác trong hình ảnh bên phải bằng cách sử dụng thước tuỳ chỉnh như trong mã mẫu trước đó.
Xác minh rằng các thành phần mẹ bị ràng buộc
Để sử dụng WindowInsetsRulers một cách an toàn, hãy đảm bảo thành phần mẹ cung cấp các quy tắ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 thành phần kết hợp mẹ.
Tương tự, việc đặt một composable sử dụng WindowInsetsRulers bên trong một vùng chứa cuộn như verticalScroll có thể gây ra Hành vi không mong muốn vì vùng chứa cuộn cung cấp các giới hạn về Chiều cao không giới hạn, không tương thích với logic của thước kẻ.







