Sau khi bạn nhắm đến SDK 35 trở lên trên một thiết bị chạy Android 15 trở lên, ứng dụng của bạn sẽ hiển thị tràn viền. Cửa sổ trải dài toàn bộ chiều rộng và chiều cao của màn hình bằng cách vẽ phía sau các thanh hệ thống. Thanh hệ thống bao gồm thanh trạng thái, thanh chú thích và thanh điều hướng.
Nhiều ứng dụng có thanh ứng dụng trên cùng. Thanh ứng dụng trên cùng phải kéo dài đến cạnh trên cùng của màn hình và hiển thị phía sau thanh trạng thái. Bạn có thể thu nhỏ thanh ứng dụng trên cùng xuống chiều cao của thanh trạng thái khi nội dung cuộn.
Nhiều ứng dụng cũng có thanh ứng dụng dưới cùng hoặc thanh điều hướng dưới cùng. Các thanh này cũng phải kéo dài đến cạnh dưới cùng của màn hình và hiển thị phía sau thanh điều hướng. Nếu không, ứng dụng sẽ hiển thị nội dung cuộn phía sau thanh điều hướng.
Khi triển khai bố cục tràn viền trong ứng dụng, hãy lưu ý những điều sau:
- Bật màn hình tràn viền
- Xử lý mọi hình ảnh trùng lặp.
- Cân nhắc hiển thị màn hình chờ phía sau các thanh hệ thống.
Cho phép hiển thị tràn viền
Nếu ứng dụng của bạn nhắm đến SDK 35 trở lên, chế độ tràn viền sẽ tự động bật cho các thiết bị chạy Android 15 trở lên.
Để bật chế độ tràn viền trên các phiên bản Android trước, hãy làm như sau:
Thêm phần phụ thuộc vào thư viện
androidx.activity
trong tệpbuild.gradle
của ứng dụng hoặc mô-đun:Kotlin
dependencies { val activity_version =
activity_version
// Java language implementation implementation("androidx.activity:activity:$activity_version") // Kotlin implementation("androidx.activity:activity-ktx:$activity_version") }Groovy
dependencies { def activity_version =
activity_version
// Java language implementation implementation 'androidx.activity:activity:$activity_version' // Kotlin implementation 'androidx.activity:activity-ktx:$activity_version' }Nhập hàm mở rộng
enableEdgeToEdge
vào ứng dụng:
Bật chế độ tràn viền theo cách thủ công bằng cách gọi enableEdgeToEdge
trong onCreate
của Activity
. Bạn nên gọi phương thức này trước setContentView
.
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) ... }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { EdgeToEdge.enable(this); super.onCreate(savedInstanceState); ... }
Theo mặc định, enableEdgeToEdge()
làm cho các thanh hệ thống trong suốt, ngoại trừ chế độ điều hướng bằng 3 nút, trong đó thanh trạng thái có một màn chắn trong suốt. Màu sắc của các biểu tượng hệ thống và màn chắn được điều chỉnh dựa trên giao diện sáng hoặc tối của hệ thống.
Hàm enableEdgeToEdge()
tự động khai báo rằng ứng dụng phải được bố trí cạnh nhau và điều chỉnh màu sắc của các thanh hệ thống.
Để bật màn hình tràn viền trong ứng dụng mà không cần sử dụng hàm enableEdgeToEdge()
, hãy xem phần Thiết lập màn hình tràn viền theo cách thủ công.
Xử lý các phần chồng chéo bằng phần lồng ghép
Một số thành phần hiển thị của ứng dụng có thể vẽ phía sau các thanh hệ thống, như trong hình 3.
Bạn có thể giải quyết vấn đề chồng chéo bằng cách phản ứng với các phần lồng ghép, trong đó chỉ định những phần nào của màn hình giao nhau với giao diện người dùng hệ thống, chẳng hạn như thanh điều hướng hoặc thanh trạng thái. Giao nhau có thể có nghĩa là hiển thị phía trên nội dung, nhưng cũng có thể thông báo cho ứng dụng của bạn về các cử chỉ hệ thống.
Các loại phần lồng ghép áp dụng cho việc hiển thị ứng dụng tràn viền bao gồm:
Phần lồng ghép thanh hệ thống: phù hợp nhất với các thành phần hiển thị có thể nhấn và không được bị các thanh hệ thống che khuất.
Vùng lồng ghép phần cắt trên màn hình: dành cho các khu vực có thể có phần cắt trên màn hình do hình dạng của thiết bị.
Phần lồng ghép cử chỉ của hệ thống: dành cho các khu vực điều hướng bằng cử chỉ mà hệ thống sử dụng và có mức độ ưu tiên cao hơn ứng dụng của bạn.
Lồng ghép thanh hệ thống
Phần lồng ghép thanh hệ thống là loại phần lồng ghép được sử dụng phổ biến nhất. Các vùng này đại diện cho khu vực mà giao diện người dùng hệ thống hiển thị theo trục Z phía trên ứng dụng. Bạn nên sử dụng các vùng này để di chuyển hoặc đệm các thành phần hiển thị có thể nhấn trong ứng dụng và không được bị các thanh hệ thống che khuất.
Ví dụ: nút hành động nổi (FAB) trong hình 3 bị thanh điều hướng che khuất một phần:
Để tránh tình trạng chồng chéo hình ảnh này ở chế độ cử chỉ hoặc chế độ nút, bạn có thể tăng lề của thành phần hiển thị bằng cách sử dụng getInsets(int)
với WindowInsetsCompat.Type.systemBars()
.
Mã ví dụ sau đây cho thấy cách triển khai phần lồng ghép thanh hệ thống:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) // Apply the insets as a margin to the view. This solution sets // only the bottom, left, and right dimensions, but you can apply whichever // insets are appropriate to your layout. You can also update the view padding // if that's more appropriate. v.updateLayoutParams<MarginLayoutParams> { leftMargin = insets.left bottomMargin = insets.bottom rightMargin = insets.right } // Return CONSUMED if you don't want want the window insets to keep passing // down to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); // Apply the insets as a margin to the view. This solution sets only the // bottom, left, and right dimensions, but you can apply whichever insets are // appropriate to your layout. You can also update the view padding if that's // more appropriate. MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams(); mlp.leftMargin = insets.left; mlp.bottomMargin = insets.bottom; mlp.rightMargin = insets.right; v.setLayoutParams(mlp); // Return CONSUMED if you don't want want the window insets to keep passing // down to descendant views. return WindowInsetsCompat.CONSUMED; });
Nếu bạn áp dụng giải pháp này cho ví dụ trong hình 3, thì sẽ không có hình ảnh chồng chéo trong chế độ nút, như minh hoạ trong hình 4:
Điều tương tự cũng áp dụng cho chế độ điều hướng bằng cử chỉ, như minh hoạ trong hình 5:
Hiển thị phần lồng ghép vết cắt
Một số thiết bị có phần cắt màn hình. Thông thường, phần cắt nằm ở đầu màn hình và nằm trong thanh trạng thái. Khi màn hình thiết bị ở chế độ ngang, phần cắt có thể nằm ở cạnh dọc. Tuỳ thuộc vào nội dung mà ứng dụng hiển thị trên màn hình, bạn nên triển khai khoảng đệm để tránh các phần cắt trên màn hình, vì theo mặc định, các ứng dụng sẽ vẽ trong phần cắt trên màn hình.
Ví dụ: nhiều màn hình ứng dụng hiển thị danh sách các mục. Không che khuất các mục trong danh sách bằng phần cắt màn hình hoặc thanh hệ thống.
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets -> val bars = insets.getInsets( WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() ) v.updatePadding( left = bars.left, top = bars.top, right = bars.right, bottom = bars.bottom, ) WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> { Insets bars = insets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() ); v.setPadding(bars.left, bars.top, bars.right, bars.bottom); return WindowInsetsCompat.CONSUMED; });
Xác định giá trị của WindowInsetsCompat
bằng cách lấy hoặc logic của các thanh hệ thống và các loại phần cắt màn hình.
Đặt clipToPadding
thành RecyclerView
để khoảng đệm cuộn cùng với các mục trong danh sách. Điều này cho phép các mục nằm phía sau các thanh hệ thống khi người dùng cuộn, như trong ví dụ sau.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
Phần lồng ghép cử chỉ hệ thống
Phần lồng ghép cử chỉ hệ thống đại diện cho các khu vực của cửa sổ mà cử chỉ hệ thống được ưu tiên hơn ứng dụng của bạn. Các khu vực này được thể hiện bằng màu cam trong hình 6:
Giống như các phần lồng ghép thanh hệ thống, bạn có thể tránh chồng chéo các phần lồng ghép cử chỉ hệ thống bằng cách sử dụng getInsets(int)
với WindowInsetsCompat.Type.systemGestures()
.
Sử dụng các phần lồng ghép này để di chuyển hoặc đệm các thành phần hiển thị có thể vuốt ra khỏi các cạnh. Các trường hợp sử dụng phổ biến bao gồm trang dưới cùng, thao tác vuốt trong trò chơi và băng chuyền được triển khai bằng ViewPager2
.
Trên Android 10 trở lên, phần lồng ghép thao tác hệ thống chứa phần lồng ghép dưới cùng cho thao tác về màn hình chính, và phần lồng ghép bên trái và bên phải cho thao tác quay lại:
Mã ví dụ sau đây cho thấy cách triển khai phần lồng ghép cử chỉ hệ thống:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()) // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.updatePadding(insets.left, insets.top, insets.right, insets.bottom) // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()); // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.setPadding(insets.left, insets.top, insets.right, insets.bottom); // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. return WindowInsetsCompat.CONSUMED; });
Thành phần Material
Nhiều Thành phần Material của Android dựa trên khung hiển thị (com.google.android.material){:.external} tự động xử lý phần lồng ghép, bao gồm cả BottomAppBar
, BottomNavigationView
, NavigationRailView
và NavigationView
Tuy nhiên, AppBarLayout
không tự động xử lý các phần lồng ghép. Thêm android:fitsSystemWindows="true"
để xử lý các phần lồng ghép trên cùng.
Đọc cách xử lý phần lồng ghép bằng Thành phần Material trong Compose.
Chế độ hiển thị tối đa
Một số nội dung nên được xem ở chế độ toàn màn hình để mang đến cho người dùng trải nghiệm sống động hơn. Bạn có thể ẩn thanh hệ thống cho chế độ hiển thị tối đa bằng cách sử dụng thư viện WindowInsetsController
và WindowInsetsControllerCompat
:
Kotlin
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) // Hide the system bars. windowInsetsController.hide(Type.systemBars()) // Show the system bars. windowInsetsController.show(Type.systemBars())
Java
Window window = getWindow(); WindowInsetsControllerCompat windowInsetsController = WindowCompat.getInsetsController(window, window.getDecorView()); if (windowInsetsController == null) { return; } // Hide the system bars. windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); // Show the system bars. windowInsetsController.show(WindowInsetsCompat.Type.systemBars());
Hãy tham khảo phần Ẩn thanh hệ thống cho chế độ chìm để biết thêm thông tin về cách triển khai tính năng này.
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 khác
Hãy xem các tài liệu tham khảo sau đây để biết thêm thông tin về WindowInsets
, thao tác bằng cử chỉ và cách hoạt động của phần lồng ghép:
- Thanh hệ thống Android
- Mẹo xử lý phần lồng ghép cho biện pháp thực thi chế độ tràn viền của Android 15
- WindowInsets – trình nghe bố cục
- Thao tác bằng cử chỉ: Phần lồng ghép
- Cách hoạt động của phần lồng ghép trên Android?