Hiển thị nội dung tràn viền trong ứng dụng của bạn và xử lý các phần lồng ghép cửa sổ trong Compose

Nền tảng Android chịu trách nhiệm vẽ giao diện người dùng hệ thống, chẳng hạn như thanh trạng thái và thanh điều hướng. Giao diện người dùng hệ thống này sẽ hiển thị bất kể người dùng đang sử dụng ứng dụng nào.

WindowInsets cung cấp thông tin về giao diện người dùng hệ thống để đảm bảo ứng dụng của bạn vẽ ở đúng khu vực và giao diện người dùng không bị giao diện người dùng hệ thống che khuất.

Hiển thị tràn viền để vẽ phía sau các thanh hệ thống
Hình 1. Hiển thị tràn viền để vẽ phía sau các thanh hệ thống.

Trên Android 14 (API cấp 34) trở xuống, giao diện người dùng của ứng dụng sẽ không vẽ bên dưới các thanh hệ thống và vết cắt trên màn hình theo mặc định.

Trên Android 15 (API cấp 35) trở lên, ứng dụng của bạn sẽ vẽ bên dưới các thanh hệ thống và hiển thị các phần cắt khi ứng dụng nhắm đến SDK 35. Điều này mang lại trải nghiệm liền mạch hơn cho người dùng và cho phép ứng dụng của bạn tận dụng tối đa không gian cửa sổ có sẵn.

Việc hiển thị nội dung phía sau giao diện người dùng hệ thống được gọi là chuyển sang chế độ tràn viền. Trên trang này, bạn sẽ tìm hiểu về các loại phần lồng ghép, cách hiển thị tràn viền và cách sử dụng API phần lồng ghép để tạo ảnh động cho giao diện người dùng và đảm bảo nội dung của ứng dụng không bị các thành phần trên giao diện người dùng hệ thống che khuất.

Kiến thức cơ bản về phần lồng ghép

Khi một ứng dụng chạy tràn viền, bạn cần đảm bảo rằng giao diện người dùng hệ thống không che khuất nội dung và hoạt động tương tác quan trọng. Ví dụ: nếu một nút được đặt phía sau thanh điều hướng, thì người dùng có thể không nhấp được vào nút đó.

Kích thước của giao diện người dùng hệ thống và thông tin về vị trí đặt giao diện người dùng được chỉ định thông qua phần lồng ghép.

Mỗi phần của giao diện người dùng hệ thống có một loại phần lồng ghép tương ứng mô tả kích thước và vị trí của phần lồng ghép đó. Ví dụ: phần lồng ghép thanh trạng thái cung cấp kích thước và vị trí của thanh trạng thái, trong khi phần lồng ghép thanh điều hướng cung cấp kích thước và vị trí của thanh điều hướng. Mỗi loại phần lồng ghép bao gồm 4 kích thước pixel: trên cùng, bên trái, bên phải và dưới cùng. Các kích thước này chỉ định khoảng cách mà giao diện người dùng hệ thống mở rộng từ các cạnh tương ứng của cửa sổ ứng dụng. Do đó, để tránh trùng lặp với loại giao diện người dùng hệ thống đó, giao diện người dùng ứng dụng phải được lồng ghép theo lượng đó.

Các loại phần lồng ghép Android tích hợp sẵn này có sẵn thông qua WindowInsets:

WindowInsets.statusBars

Phần lồng ghép mô tả các thanh trạng thái. Đây là các thanh giao diện người dùng hệ thống trên cùng chứa biểu tượng thông báo và các chỉ báo khác.

WindowInsets.statusBarsIgnoringVisibility

Các phần lồng ghép thanh trạng thái khi chúng hiển thị. Nếu thanh trạng thái hiện đang ẩn (do chuyển sang chế độ toàn màn hình sống động), thì các phần lồng ghép thanh trạng thái chính sẽ trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.navigationBars

Phần lồng ghép mô tả các thanh điều hướng. Đây là các thanh giao diện người dùng hệ thống ở bên trái, bên phải hoặc bên dưới thiết bị, mô tả thanh tác vụ hoặc biểu tượng điều hướng. Các thành phần này có thể thay đổi trong thời gian chạy dựa trên phương thức điều hướng mà người dùng ưu tiên và tương tác với thanh tác vụ.

WindowInsets.navigationBarsIgnoringVisibility

Các phần lồng ghép thanh điều hướng khi chúng hiển thị. Nếu các thanh điều hướng hiện đang bị ẩn (do chuyển sang chế độ toàn màn hình sống động), thì các phần lồng ghép thanh điều hướng chính sẽ trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.captionBar

Phần lồng ghép mô tả kiểu trang trí cửa sổ giao diện người dùng hệ thống nếu ở cửa sổ dạng tự do, chẳng hạn như thanh tiêu đề trên cùng.

WindowInsets.captionBarIgnoringVisibility

Phần lồng ghép thanh phụ đề khi chúng hiển thị. Nếu các thanh chú thích hiện đang bị ẩn, thì các phần lồng ghép của thanh chú thích chính sẽ trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.systemBars

Tập hợp các phần lồng ghép của thanh hệ thống, bao gồm thanh trạng thái, thanh điều hướng và thanh chú thích.

WindowInsets.systemBarsIgnoringVisibility

Các phần lồng ghép thanh hệ thống khi chúng hiển thị. Nếu các thanh hệ thống hiện đang bị ẩn (do chuyển sang chế độ toàn màn hình sống động), thì các phần lồng ghép thanh hệ thống chính sẽ trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.ime

Phần lồng ghép mô tả dung lượng không gian ở dưới cùng mà bàn phím phần mềm chiếm dụng.

WindowInsets.imeAnimationSource

Các phần lồng ghép mô tả lượng không gian mà bàn phím phần mềm chiếm trước ảnh động bàn phím hiện tại.

WindowInsets.imeAnimationTarget

Phần lồng ghép mô tả không gian mà bàn phím phần mềm sẽ chiếm sau ảnh động bàn phím hiện tại.

WindowInsets.tappableElement

Một loại phần lồng ghép mô tả thông tin chi tiết hơn về giao diện người dùng điều hướng, cho biết lượng không gian mà hệ thống sẽ xử lý "lượt nhấn" chứ không phải ứng dụng. Đối với thanh điều hướng trong suốt có tính năng điều hướng bằng cử chỉ, bạn có thể nhấn vào một số thành phần ứng dụng thông qua giao diện người dùng điều hướng của hệ thống.

WindowInsets.tappableElementIgnoringVisibility

Phần tử có thể nhấn sẽ lồng ghép vào khi hiển thị. Nếu các phần tử có thể nhấn hiện đang bị ẩn (do chuyển sang chế độ toàn màn hình sống động), thì các phần lồng ghép phần tử có thể nhấn chính sẽ trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.systemGestures

Phần lồng ghép đại diện cho số lượng phần lồng ghép mà hệ thống sẽ chặn cử chỉ để điều hướng. Các ứng dụng có thể chỉ định xử lý một số lượng hạn chế các cử chỉ này theo cách thủ công thông qua Modifier.systemGestureExclusion.

WindowInsets.mandatorySystemGestures

Một tập hợp con của các cử chỉ hệ thống sẽ luôn do hệ thống xử lý và không thể chọn không sử dụng thông qua Modifier.systemGestureExclusion.

WindowInsets.displayCutout

Phần lồng ghép thể hiện khoảng cách cần thiết để tránh chồng chéo với phần cắt trên màn hình (vết khía hoặc lỗ pin).

WindowInsets.waterfall

Phần lồng ghép đại diện cho các khu vực cong của màn hình dạng thác nước. Màn hình thác nước có các vùng cong dọc theo các cạnh của màn hình, nơi màn hình bắt đầu bao bọc dọc theo các cạnh của thiết bị.

Các loại này được tóm tắt theo 3 loại phần lồng ghép "an toàn" để đảm bảo nội dung không bị che khuất:

Các loại phần lồng ghép "an toàn" này bảo vệ nội dung theo nhiều cách, dựa trên phần lồng ghép nền tảng cơ bản:

  • Sử dụng WindowInsets.safeDrawing để bảo vệ nội dung không được vẽ bên dưới bất kỳ giao diện người dùng hệ thống nào. Đây là cách sử dụng lồng ghép phổ biến nhất: để ngăn nội dung vẽ bị giao diện người dùng hệ thống che khuất (một phần hoặc hoàn toàn).
  • Sử dụng WindowInsets.safeGestures để bảo vệ nội dung bằng cử chỉ. Điều này giúp tránh các cử chỉ của hệ thống xung đột với cử chỉ của ứng dụng (chẳng hạn như các cử chỉ cho các trang dưới cùng, băng chuyền hoặc trong trò chơi).
  • Sử dụng WindowInsets.safeContent dưới dạng kết hợp giữa WindowInsets.safeDrawingWindowInsets.safeGestures để đảm bảo nội dung không bị chồng chéo về hình ảnh và không bị chồng chéo về cử chỉ.

Thiết lập phần lồng ghép

Để cho phép ứng dụng của bạn có toàn quyền kiểm soát vị trí vẽ nội dung, hãy làm theo các bước thiết lập sau. Nếu không thực hiện các bước này, ứng dụng của bạn có thể vẽ màu đen hoặc màu đồng nhất phía sau giao diện người dùng hệ thống hoặc không tạo ảnh động đồng bộ với bàn phím phần mềm.

  1. Nhắm đến SDK 35 trở lên để thực thi chế độ tràn viền trên Android 15 trở lên. Ứng dụng của bạn hiển thị phía sau giao diện người dùng hệ thống. Bạn có thể điều chỉnh giao diện người dùng của ứng dụng bằng cách xử lý các phần lồng ghép.
  2. Bạn có thể gọi enableEdgeToEdge() trong Activity.onCreate() để cho phép ứng dụng của bạn hiển thị tràn viền trên các phiên bản Android trước.
  3. Đặt android:windowSoftInputMode="adjustResize" trong mục nhập AndroidManifest.xml của Hoạt động. Chế độ cài đặt này cho phép ứng dụng của bạn nhận kích thước của IME phần mềm dưới dạng phần lồng ghép. Bạn có thể sử dụng chế độ cài đặt này để đệm và bố trí nội dung một cách phù hợp khi IME xuất hiện và biến mất trong ứng dụng.

    <!-- in your AndroidManifest.xml file: -->
    <activity
      android:name=".ui.MainActivity"
      android:label="@string/app_name"
      android:windowSoftInputMode="adjustResize"
      android:theme="@style/Theme.MyApplication"
      android:exported="true">
    

API Compose

Sau khi Hoạt động của bạ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 để đảm bảo rằng nội dung không bị che khuất và các phần tử 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.

Ví dụ: đây là phương thức cơ bản nhất để áp dụng phần lồng ghép vào 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ó ứng dụng nào sẽ vẽ phía sau giao diện người dùng hệ thống để đạt được hiệu ứng tràn viền. Để khai thác tối đa toàn bộ cửa sổ, bạn cần điều chỉnh chính xác vị trí áp dụng phần lồng ghép trên cơ sở màn hình hoặc 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 điều chỉnh cho phiên bản cũ xuống API 21. Ngoài ra, 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ị lồng ghép thay đổi.

Có hai cách chính để sử dụng các loại phần lồng ghép này nhằm điều chỉnh bố cục Thành phần kết hợp: đối tượng sửa đổi khoảng đệm và đối tượng sửa đổi kích thước phần lồng ghép.

Đố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 bản vẽ an toàn làm khoảng đệm trên 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 trong những phương thức như vậy, tương đương với Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Có các đối tượng sửa đổi tương tự cho các loại phần lồng ghép khác.

Đối tượng sửa đổi kích thước phần lồng ghép

Các đối tượng sửa đổi sau đây áp dụng một số 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:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

Áp dụng cạnh bắt đầu của windowInsets làm chiều rộng (như Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Áp dụng cạnh cuối của windowInsets làm chiều rộng (như Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

Áp dụng cạnh trên của windowInsets làm chiều cao (như Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Áp dụng cạnh dưới của windowInsets làm chiều cao (như Modifier.height)

Các đối tượng sửa đổi này đặc biệt hữu ích khi định cỡ 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

Các đối tượng sửa đổi khoảng đệm lồng ghép (windowInsetsPadding và các trình trợ giúp như safeDrawingPadding) sẽ 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 sẽ 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 và 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 việc lãng phí quá nhiều không gian.

Đố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 lồng ghép nhiều lần nếu phần lồng ghép đã được sử dụng. Tuy nhiên, vì đang thay đổi kích thước trực tiếp nên các thành phần này không tự sử dụng phần lồng ghép.

Do đó, các đối tượng sửa đổi khoảng đệm lồng nhau sẽ tự động thay đổi lượng khoảng đệm áp dụng cho từng thành phần kết hợp.

Xem xét cùng một ví dụ về LazyColumn như trước, LazyColumn đang được đối tượng sửa đổi imePadding đổi kích thước. Bên trong LazyColumn, mục cuối cùng được định kích thước bằng chiều cao của phần cuối thanh hệ thống:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Khi IME đóng, đối tượng sửa đổi imePadding() sẽ không áp dụng khoảng đệm, vì IME không có chiều cao. Vì đối tượng sửa đổi imePadding() không áp dụng khoảng đệm, nên không có phần lồng ghép nào được sử dụng và chiều cao của Spacer sẽ là kích thước của cạnh dưới cùng của các thanh hệ thống.

Khi IME mở ra, 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() sẽ bắt đầu áp dụng khoảng đệm dưới cùng để đổi kích thước LazyColumn khi IME mở ra. 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 số 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 đối tượng sửa đổi imePadding() áp dụng. Khi đối tượng sửa đổi imePadding() đang á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 bắt đầu mở rộng từ chiều cao bằng 0 khi imePadding() áp dụng ít hơn cạnh dưới của các thanh hệ thống, cho đến khi Spacer khớp với chiều cao của cạnh dưới của các thanh hệ thống sau khi IME hoàn toàn biến mất.

Hình 2. Cột tải lười từ cạnh này sang cạnh kia bằ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 giống 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 các đố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 số 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 sẽ lấy một PaddingValues tuỳ ý để sử dụng. Điều này rất hữu ích để 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 đệm 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 phần lồng ghép cửa sổ thô mà không cần tiêu thụ, hãy sử dụng trực tiếp các giá trị WindowInsets hoặc sử dụng WindowInsets.asPaddingValues() để trả về PaddingValues của các phần lồng ghép không bị ảnh hưởng bởi mức tiêu thụ. Tuy nhiên, do các lưu ý dưới đây, 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 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 phần lồng ghép, trong đó sử dụng các API nền tảng cơ bản để quản lý 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 phần lồng ghép trong thành phần kết hợp thường sử dụng giá trị của phần lồng ghép chậm 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 tạo để trì hoãn việc sử dụng các giá trị của phần lồng ghép cho đến giai đoạn bố cục, đảm bảo rằng các giá trị lồng ghép được sử dụng trên cùng một khung khi được cập nhật.

Ảnh động IME của bàn phím bằng WindowInsets

Bạn có thể áp dụng Modifier.imeNestedScroll() cho một vùng chứa cuộn để tự động mở và đóng IME khi cuộn xuống cuối vùng chứa.

class WindowInsetsExampleActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        WindowCompat.setDecorFitsSystemWindows(window, false)

        setContent {
            MaterialTheme {
                MyScreen()
            }
        }
    }
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun MyScreen() {
    Box {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize() // fill the entire window
                .imePadding() // padding for the bottom for the IME
                .imeNestedScroll(), // scroll IME at the bottom
            content = { }
        )
        FloatingActionButton(
            modifier = Modifier
                .align(Alignment.BottomEnd)
                .padding(16.dp) // normal 16dp of padding for FABs
                .navigationBarsPadding() // padding for navigation bar
                .imePadding(), // padding for when IME appears
            onClick = { }
        ) {
            Icon(imageVector = Icons.Filled.Add, contentDescription = "Add")
        }
    }
}

Ảnh động hiển thị phần tử giao diện người dùng cuộn lên và xuống để nhường chỗ cho bàn phím
Hình 3. Ảnh động IME.

Hỗ trợ phần lồng ghép cho Thành phần Material 3

Để dễ sử dụng, nhiều thành phần kết hợp Material 3 tích hợp sẵn (androidx.compose.material3) tự xử lý phần lồng ghép, dựa trên cách các thành phần kết hợp được đặt trong ứng dụng theo thông số kỹ thuật của Material.

Thành phần kết hợp xử lý phần lồng ghép

Dưới đây là danh sách Thành phần Material tự động xử lý phần lồng ghép.

Thanh ứng dụng

Vùng chứa nội dung

Scaffold

Theo mặc định, Scaffold cung cấp các phần lồng ghép dưới dạng tham số paddingValues để bạn sử dụng. Scaffold không áp dụng phần lồng ghép cho nội dung; bạn phải chịu trách nhiệm về việc này. Ví dụ: để sử dụng các phần lồng ghép này bằng LazyColumn bên trong Scaffold:

Scaffold { innerPadding ->
    // innerPadding contains inset information for you to use and apply
    LazyColumn(
        // consume insets as scaffold doesn't do it by default
        modifier = Modifier.consumeWindowInsets(innerPadding),
        contentPadding = innerPadding
    ) {
        items(count = 100) {
            Box(
                Modifier
                    .fillMaxWidth()
                    .height(50.dp)
                    .background(colors[it % colors.size])
            )
        }
    }
}

Ghi đè phần lồng ghép mặc định

Bạn có thể thay đổi tham số windowInsets được truyền đến thành phần kết hợp để định cấu hình hành vi của thành phần kết hợp. Tham số này có thể là một loại phần lồng ghép cửa sổ khác để áp dụng hoặc bị tắt bằng cách truyền một thực thể trống: WindowInsets(0, 0, 0, 0).

Ví dụ: để tắt tính năng xử lý phần lồng ghép trên LargeTopAppBar, hãy đặt tham số windowInsets thành một thực thể trống:

LargeTopAppBar(
    windowInsets = WindowInsets(0, 0, 0, 0),
    title = {
        Text("Hi")
    }
)

Tương tác với các phần lồng ghép của hệ thống Khung hiển thị

Bạn có thể cần ghi đè phần lồng ghép mặc định khi màn hình có cả Khung hiển thị và mã Compose trong cùng một hệ phân cấp. Trong trường hợp này, bạn cần nêu rõ phần lồng ghép nào sẽ được sử dụng và phần lồng ghép nào sẽ bị bỏ qua.

Ví dụ: nếu bố cục ngoài cùng của bạn là bố cục Khung hiển thị Android, bạn nên sử dụng các phần lồng ghép trong hệ thống Khung hiển thị và bỏ qua các phần lồng ghép đó cho Compose. Ngoài ra, nếu bố cục ngoài cùng của bạn là một thành phần kết hợp, bạn nên sử dụng các phần lồng ghép trong Compose và đệm các thành phần kết hợp AndroidView cho phù hợp.

Theo mặc định, mỗi ComposeView sẽ sử dụng tất cả các phần lồng ghép ở mức tiêu thụ WindowInsetsCompat. Để thay đổi hành vi mặc định này, hãy đặt ComposeView.consumeWindowInsets thành false.

Bảo vệ thanh hệ thống

Sau khi ứng dụng của bạn nhắm đến SDK 35 trở lên, chế độ tràn viền sẽ được thực thi. Thanh trạng thái hệ thống và thanh điều hướng bằng cử chỉ có màu trong suốt, nhưng thanh điều hướng bằng 3 nút có màu trong mờ.

Để xoá tính năng bảo vệ trong nền của chế độ thao tác bằng 3 nút có màu trong mờ theo mặc định, hãy đặt Window.setNavigationBarContrastEnforced thành false.

Tài nguyên