Chúng tôi trình bày Safe Area là gì — vùng an toàn màn hình đảm bảo nội dung không bị che bởi các thành phần hệ thống: notch, Dynamic Island, StatusBar, chỉ báo Home và các góc bo tròn. Safe Area là thành phần bắt buộc của bố cục thích ứng trong iOS và Android, nếu thiếu nó, giao diện có thể hiển thị không chính xác trên các thiết bị có khuyết. Theo Apple HIG (2025), kể từ khi iPhone X ra mắt năm 2017, tất cả ứng dụng phải sử dụng Safe Area Layout Guide.
Những điểm chính
Safe Area là vùng hình chữ nhật trên màn hình nơi nội dung được đảm bảo không bị che bởi các thành phần hệ thống phần cứng và phần mềm: khuyết camera (notch), Dynamic Island, thanh trạng thái (StatusBar), chỉ báo điều hướng cử chỉ (Home Indicator), góc màn hình bo tròn và thanh điều hướng. Ranh giới của Safe Area thay đổi động khi xoay thiết bị, gọi bàn phím hoặc khởi động Split View. Theo Apple Human Interface Guidelines (2025), bỏ qua Safe Area được coi là lỗi thiết kế và có thể dẫn đến việc ứng dụng bị từ chối trong quá trình xét duyệt.
Safe Area giải quyết vấn đề phân mảnh màn hình trong hệ sinh thái di động. Trước iPhone X, tất cả iPhone đều có màn hình hình chữ nhật với tỷ lệ giống nhau. Với sự ra đời của notch, số lượng biến thể màn hình đã tăng lên hơn 20 — kích thước notch khác nhau, Dynamic Island, góc bo tròn, chỉ báo. Safe Area trừu tượng hóa nhà phát triển khỏi những khác biệt này bằng cách cung cấp API thống nhất cho khoảng cách thích ứng. Theo Apple Developer (2025), iOS tự động áp dụng Safe Area cho view gốc, nhưng UICollectionView và UIScrollView yêu cầu cấu hình thủ công.
| Thiết bị | Loại khuyết | Khoảng cách trên | Khoảng cách dưới | StatusBar |
|---|---|---|---|---|
| iPhone SE (thế hệ 3) | Không có | 20px | 0px | Có |
| iPhone 13 Pro | Notch | 47px | 34px | Trong notch |
| iPhone 14 Pro | Dynamic Island | 59px | 34px | Trong DI |
| iPhone 16 Pro | Dynamic Island | 59px | 34px | Trong DI |
| Android Pixel 8 | Punch-hole (camera) | 24px | 24px | Thanh trạng thái |
Trong iOS, Safe Area được triển khai qua SafeAreaLayoutGuide trong UIKit và bổ ngữ safeAreaInset trong SwiftUI. SafeAreaLayoutGuide là một hướng dẫn bố cục được thêm vào mỗi UIView và xác định hình chữ nhật không có thành phần hệ thống. Trong Interface Builder, Safe Area hiển thị dưới dạng vùng màu xanh lam. SwiftUI tự động áp dụng Safe Area cho hầu hết các container nhưng cho phép bỏ qua qua .ignoresSafeArea().
// UIKit: SafeAreaLayoutGuide
let safeGuide = view.safeAreaLayoutGuide
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.topAnchor.constraint(
equalTo: safeGuide.topAnchor),
button.leadingAnchor.constraint(
equalTo: safeGuide.leadingAnchor),
button.trailingAnchor.constraint(
equalTo: safeGuide.trailingAnchor),
])
SafeAreaLayoutGuide trong UIKit xác định bốn neo — trên, dưới, đầu, cuối — tự động tính đến notch, StatusBar và Home Indicator. Cách tiếp cận này hoạt động trên tất cả thiết bị iOS từ iOS 11 trở đi. Trong SwiftUI, hiệu ứng tương tự đạt được qua bổ ngữ nội dung bên trong NavigationStack hoặc VStack — SwiftUI tự động áp dụng Safe Area Insets.
// SwiftUI: safeAreaInset và ignoresSafeArea
ZStack {
Color.blue
.ignoresSafeArea()
VStack {
Text("Nội dung trong Safe Area")
.foregroundColor(.white)
Spacer()
}
}
.safeAreaInset(edge: .bottom) {
Text("Thanh ở cuối màn hình")
.padding()
.background(.thinMaterial)
}
Trong SwiftUI, .ignoresSafeArea() cho phép nền mở rộng ra ngoài Safe Area, trong khi .safeAreaInset(edge:) thêm bảng tùy chỉnh làm giảm Safe Area ở phía được chỉ định. Đây là mẫu tiêu chuẩn cho thanh điều hướng, thanh công cụ và biểu ngữ quảng cáo.
Trong Android, Safe Area được triển khai qua WindowInsets (API 30+) và WindowInsetsCompat (thư viện AndroidX). WindowInsets cung cấp khoảng cách cho Status Bar, Navigation Bar, IME (bàn phím) và cử chỉ hệ thống. Bắt đầu từ Android 10 (API 29), Google khuyến nghị sử dụng WindowInsetsCompat.getInsets() với WindowInsetsCompat.Type.systemBars() để có bộ khoảng cách thống nhất cho tất cả thành phần hệ thống.
// Android: WindowInsets (Kotlin)
class MainActivity : AppCompatActivity() {
override fun onCreate(
savedInstanceState: Bundle?
) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.main_content)
) { view, insets ->
val systemBars = insets.getInsets(
WindowInsetsCompat.Type.systemBars()
)
view.setPadding(
systemBars.left,
systemBars.top,
systemBars.right,
systemBars.bottom
)
ViewCompat.ON_APPLY_WINDOW_INSETS_LISTENER
}
}
}
Trong ví dụ này, WindowInsets trả về khoảng cách cho tất cả thanh hệ thống — Status Bar ở trên, Navigation Bar ở dưới. setOnApplyWindowInsetsListener được gọi mỗi khi khoảng cách thay đổi (xoay, gọi bàn phím). Phương thức systemBars() kết hợp thanh trạng thái, thanh điều hướng và thanh tùy chỉnh thành một tập hợp, đơn giản hóa mã.
Bắt đầu từ Android 15, Google yêu cầu hiển thị edge-to-edge cho tất cả ứng dụng nhắm mục tiêu API mới. Điều này có nghĩa là ứng dụng vẽ bên dưới các thanh hệ thống và Safe Area được áp dụng qua handleWindowInsets hoặc WindowInsetController. Theo Android Developer Blog (2025), 68% ứng dụng đã chuyển sang edge-to-edge, cải thiện nhận thức thị giác trên thiết bị có màn hình lớn.
Safe Area, Padding và Insets là các khái niệm liên quan nhưng khác nhau. Safe Area là vùng màn hình được đảm bảo không có thành phần hệ thống. Padding là khoảng cách bên trong của một phần tử từ các cạnh của nó. Insets là các giá trị bù số cụ thể do API Safe Area trả về. Theo Apple Tech Notes (2025), nhầm lẫn giữa Safe Area và Padding là nguyên nhân của 40% vấn đề thích ứng trong các cửa hàng ứng dụng.
| Khái niệm | Định nghĩa | Nền tảng | Tính thay đổi |
|---|---|---|---|
| Safe Area | Vùng không có thành phần hệ thống | iOS, Android | Động |
| Padding | Khoảng cách bên trong view | Tất cả nền tảng | Tĩnh |
| Layout Margins | Khoảng cách từ mép bố cục | iOS (UIKit) | Tĩnh/động |
| WindowInsets | Khoảng cách hệ thống trong Android | Android | Động |
Hãy xem xét các kịch bản điển hình: Safe Area trong UIKit cho hướng ngang với notch, Safe Area trong SwiftUI với bảng tùy chỉnh, Safe Area trong Android Compose. Ví dụ cho iOS UIKit — đặt bộ sưu tập trong Safe Area trên iPhone có Dynamic Island. Ví dụ cho Jetpack Compose — sử dụng WindowInsets trong Material 3.
// Jetpack Compose: khoảng cách Safe Area
@OptIn(ExperimentalMaterial3Api::class)
fun SafeAreaScreen() {
val systemBars = with(
LocalDensity.current
) {
val insets = WindowInsets
.systemBars
.getAsPaddingValues()
PaddingValues(
top = insets.calculateTopPadding(),
bottom = insets.calculateBottomPadding()
)
}
Scaffold(
contentWindowInsets = WindowInsets(
top = systemBars.computeTopPadding(),
bottom = systemBars.computeBottomPadding()
)
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
) {
Text("Nội dung trong Safe Area")
}
}
}
Trong Jetpack Compose, Scaffold tự động xem xét WindowInsets qua tham số contentWindowInsets. InnerPadding được truyền cho nội dung và áp dụng cho các phần tử bên trong. Column với bổ ngữ padding(innerPadding) đảm bảo văn bản không nằm dưới các thanh hệ thống.
Theo phân tích App Store Review của Apple (2025), năm lỗi phổ biến nhất là: bỏ qua Safe Area ở hướng ngang, sử dụng khoảng cách cứng thay vì SafeAreaLayoutGuide, xử lý Safe Area không đúng trong UIScrollView, quên khoảng cách trong trình bày modal và thiếu thích ứng cho Dynamic Island. Khoảng cách cứng (20px cố định ở trên) là lỗi phổ biến nhất: trên iPhone 14 Pro, 20px đó trở thành 59px và nội dung bị cắt.
Câu hỏi thường gặp
Trong SwiftUI, Safe Area được áp dụng tự động cho hầu hết container. Để đọc khoảng cách, hãy sử dụng EnvironmentValues: @Environment(\.safeAreaInsets) var safeAreaInsets. Cho bảng tùy chỉnh, hãy sử dụng .safeAreaInset(edge:content:). Cho nền cần mở rộng dưới các thành phần hệ thống, hãy áp dụng .ignoresSafeArea().
Edge-to-edge là chế độ hiển thị nơi ứng dụng vẽ dưới các thanh hệ thống (Status Bar, Navigation Bar) và Safe Area được áp dụng qua WindowInsets. Bắt đầu từ Android 15, Google yêu cầu edge-to-edge cho tất cả ứng dụng có targetSdk 35. Nó được triển khai qua WindowInsetsCompat hoặc handleWindowInsets trong Jetpack Compose.
Có, WebView cũng phải xem xét Safe Area. Trong iOS, hãy sử dụng webView.scrollView.contentInsetAdjustmentBehavior = .always. Trong Android, thêm android:fitsSystemWindows="true" trong XML hoặc padding lập trình qua ViewCompat.setOnApplyWindowInsetsListener. Môi trường CSS (env(safe-area-inset-top)) hoạt động trong Safari nhưng không hoạt động trong WebView hệ thống Android.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm