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 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 rằng ứng dụng vẽ vào đúng vùng, đồng thời giao diện người dùng không bị giao diện người dùng hệ thống che khuất.

Di chuyển tràn viền để vẽ phía sau thanh hệ thống
Hình 1. Di chuyển từ cạnh này sang cạnh khác để vẽ phía sau thanh hệ thống

Theo mặc định, giao diện người dùng của ứng dụng bị hạn chế bố trí trong giao diện người dùng hệ thống, như thanh trạng thái và thanh điều hướng. Điều này đảm bảo rằng 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.

Tuy nhiên, các ứng dụng nên chọn hiển thị ở những khu vực nơi giao diện người dùng hệ thống cũng đang hiển thị, mang lại trải nghiệm người dùng liền mạch hơn và cho phép ứng dụng tận dụng tối đa không gian cửa sổ có sẵn. Tính năng này cũng cho phép các ứng dụng tạo ảnh động cùng với giao diện người dùng hệ thống, đặc biệt là khi hiện và ẩn bàn phím phần mềm.

Việc chọn hiển thị trong các khu vực này và hiển thị nội dung phía sau giao diện người dùng hệ thống được gọi là tiếp cận 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 khác nhau, cách chọn sử dụng tính năng cạnh tranh, cũng như cách sử dụng các API phần lồng ghép để tạo ảnh động cho giao diện người dùng và tránh che khuất các phần của ứng dụng.

Nguyên tắc cơ bản về phần lồng ghép

Khi một ứng dụng 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à các hoạt động tương tác quan trọng. Ví dụ: nếu một nút được đặt sau thanh điều hướng, thì người dùng có thể sẽ không nhấp vào được 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 các 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í đặt phần tử đó. Ví dụ: các 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 các 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. Để tránh tình trạng 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 với số lượng đó.

Bạn có thể sử dụng các loại phần lồng ghép Android tích hợp sẵn sau đây thông qua WindowInsets:

WindowInsets.statusBars

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

WindowInsets.statusBarsIgnoringVisibility

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

WindowInsets.navigationBars

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

WindowInsets.navigationBarsIgnoringVisibility

Phần lồng ghép thanh điều hướng cho thời điểm các phần tử này hiển thị. Nếu thanh điều hướng đ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ẽ bị 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ả việc trang trí cửa sổ giao diện người dùng hệ thống nếu ở trong một 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ụ đề cho thời điểm hiển thị. Nếu thanh phụ đề đang bị ẩn thì các phần lồng ghép thanh phụ đề chính sẽ bị trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.systemBars

Sự hợp nhất các phần lồng ghép thanh hệ thống, trong đó bao gồm thanh trạng thái, thanh điều hướng và thanh phụ đề.

WindowInsets.systemBarsIgnoringVisibility

Các phần lồng ghép thanh hệ thống cho thời điểm hiển thị. Nếu 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ẽ bị trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.ime

Các phần lồng ghép mô tả khoả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ả khoả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

Các phần lồng ghép mô tả khoảng 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 điều hướng, cho biết khoảng không gian mà hệ thống sẽ xử lý "nhấn" chứ không phải ứng dụng. Đối với các thanh điều hướng trong suốt có thao tác bằng cử chỉ, bạn có thể nhấn vào một số phần tử ứng dụng thông qua giao diện điều hướng hệ thống.

WindowInsets.tappableElementIgnoringVisibility

Các phần lồng ghép phần tử có thể nhấn vào thời điểm hiển thị các phần tử này. Nếu các phần tử có thể nhấ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 chính của phần tử có thể nhấn sẽ bị trống, nhưng các phần lồng ghép này sẽ không trống.

WindowInsets.systemGestures

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

WindowInsets.mandatorySystemGestures

Một tập hợp con 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 qua Modifier.systemGestureExclusion.

WindowInsets.displayCutout

Các 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 vết cắt trên màn hình (vết cắt hoặc lỗ kim).

WindowInsets.waterfall

Các phần lồng ghép đại diện cho các vùng cong của màn hình thác nước. Màn hình dạng thác nước có các đường cong dọc theo 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 bằng 3 kiểu phần lồng ghép "an toàn" nhằm đảm bảo nội dung không bị che khuất:

Các 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 các phần lồng ghép nền tảng cơ sở:

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

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

Để cho phép ứng dụng của bạn kiểm soát hoàn toàn vị trí vẽ nội dung, hãy làm theo các bước thiết lập sau. Nếu không có các bước này, ứng dụng của bạn có thể vẽ các màu đen hoặc đồ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. Gọi enableEdgeToEdge() trong Activity.onCreate. Lệnh gọi này yêu cầu ứng dụng của bạn hiển thị phía sau giao diện người dùng hệ thống. Sau đó, ứng dụng của bạn sẽ kiểm soát cách dùng các phần lồng ghép đó để điều chỉnh giao diện người dùng.
  2. Đặt android:windowSoftInputMode="adjustResize" trong mục 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ể dùng kích thước này để đệm và bố trí nội dung một cách thích 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ó 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 để đảm bảo 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 phần lồng ghép.

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 các phần lồng ghép cửa sổ safeDrawing làm khoảng đệm xung quanh toàn bộ nội dung ứ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 ứ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. Để tận dụng toàn bộ cửa sổ, bạn cần tinh chỉnh vị trí các phần lồng ghép được áp dụng trên từng màn hình hoặc theo từng thành phần.

Tất cả các loại phần lồng ghép này đều được tự động tạo ảnh động với ảnh động IME được điều chỉnh cho phiên bản cũ sang API 21. Theo tiện ích, tất cả bố cục sử dụng các phần lồng ghép này cũng sẽ tự động được tạo ảnh động khi các giá trị phần lồng ghép thay đổi.

Có 2 cách chính để sử dụng các loại phần lồng ghép này để đ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ổ nhất định 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 ở cả 4 mặt.

Ngoài ra, bạn cũng có thể sử dụng một số phương thức tiện ích tích hợp cho các loại phần lồng ghép phổ biến nhất. Modifier.safeDrawingPadding() là một trong các 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 số 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 là kích thước của các phần lồng ghép cửa sổ:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

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

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

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

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

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

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Áp dụng phần dưới cùng 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 trong việc định kích thướ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 sử dụng phần lồng ghép

Đối tượng sửa đổi khoảng đệm cho phần lồng ghép (windowInsetsPadding và trình trợ giúp như safeDrawingPadding) sẽ tự động sử dụng phần của các phần lồng ghép được áp dụng dưới dạng khoảng đệm. Trong khi đi sâu hơn vào cây cấu trúc, các đối tượng sửa đổi khoảng đệm lồng ghép và đối tượng sửa đổi khoảng đệm 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 phần lồng ghép bên ngoài sử dụng. Do đó, tránh sử dụng cùng một phần của các phần lồng ghép nhiều lần, điều này sẽ gây ra 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 các phần lồng ghép nhiều lần nếu các phần lồng ghép đã được sử dụng. Tuy nhiên, vì chúng trực tiếp thay đổi kích thước, nên sẽ không tự sử dụng các 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 số lượng khoảng đệm áp dụng cho mỗi thành phần kết hợp.

Xem cùng 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ó kích thước là chiều cao của đáy của các 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 sẽ không có phần lồng ghép nào được sử dụng và chiều cao của Spacer sẽ bằng kích thước của cạnh dưới cùng của thanh hệ thống.

Khi IME mở, các phần lồng ghép IME sẽ tạo hiệu ứng động cho phù hợp với kích thước của IME và công cụ 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 xuống, vì một phần khoảng cách cho thanh hệ thống đã được đối tượng sửa đổi imePadding() áp dụng. Khi đối tượng sửa đổi imePadding() áp dụng khoảng đệm dưới cùng lớn hơn thanh hệ thống, thì chiều cao của Spacer sẽ bằng 0.

Khi IME đóng, các thay đổi sẽ xảy ra ngược lại: Spacer bắt đầu mở rộng từ chiều cao bằng 0 sau khi imePadding() áp dụng nhỏ hơn phía dưới cùng của thanh hệ thống, cho đến khi Spacer cuối cùng khớp với chiều cao của phần dưới cùng của thanh hệ thống sau khi IME hoàn toàn tạo ảnh động.

Hình 2. Cột lazy cạnh này có TextField

Hành vi này được thực hiện thông qua sự giao tiếp giữa tất cả các đối tượng sửa đổi windowInsetsPadding, đồng thời có thể bị ả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 đã tiêu thụ làm khoảng đệm. Điều này 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 để chỉ báo cho các phần tử đồng cấp 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 phải sử dụng PaddingValues tuỳ ý. Điều này rất hữu ích khi thông báo cho trẻ 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 phần lồng ghép, chẳng hạn như Modifier.padding thông thường hoặc khoảng đệm chiều cao cố định:

@OptIn(ExperimentalLayoutApi::class)
Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

Trong trường hợp cần các 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ác phần lồng ghép không bị ảnh hưởng bởi việ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 cho phần lồng ghép cửa sổ và đối tượng sửa đổi kích thước phần lồng ghép cửa sổ bất cứ khi nào có thể.

Các giai đoạn có phần lồng ghép và Jetpack Compose

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, trong đó 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 các phần lồng ghép được cập nhật sau giai đoạn thành phần, 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. Đối tượng sửa đổi tích hợp sẵn mô tả trên trang này được xây dựng để 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ị phần lồng ghép được sử dụng trên cùng một khung khi được cập nhật.

Ảnh động IME trên bàn phím với 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ử trên giao diện người dùng cuộn lên và xuống để nhường chỗ cho bàn phím

Hình 1. Ảnh động IME

Hỗ trợ phần lồng ghép cho các 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ý các phần lồng ghép, dựa trên cách đặt các thành phần kết hợp trong ứng dụng theo thông số kỹ thuật của Material.

Các 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ý các 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 tiêu thụ và sử dụng. Scaffold không áp dụng các phần lồng ghép cho nội dung; trách nhiệm này là của bạn. Ví dụ: để sử dụng các phần lồng ghép này với 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 hệ thống Khung hiển thị

Bạn có thể cần phải ghi đè các 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 xác định rõ ràng xem nào sẽ sử dụng các phần lồng ghép và cái nào nên bỏ qua phần lồng ghép đó.

Ví dụ: nếu bố cục ngoài cùng là bố cục Khung hiển thị Android, thì 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 chúng cho Compose. Ngoài ra, nếu bố cục ngoài cùng 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ử dụng tất cả các phần lồng ghép ở cấp độ tiêu thụ WindowInsetsCompat. Để thay đổi hành vi mặc định này, hãy đặt ComposeView.consumeWindowInsets thành false.

Tài nguyên

  • Now in Android – một ứng dụng Android có đầy đủ chức năng được xây dựng hoàn toàn bằng Kotlin và Jetpack Compose.