Sheet là một thành phần UI xuất hiện ở cuối màn hình phía trên nội dung chính và cung cấp các hành động hoặc thông tin bổ sung. Bottom Sheet là loại phổ biến nhất, được định nghĩa trong hướng dẫn của Material Design 3 (Google, 2024). Không giống như cửa sổ hộp thoại, Sheet không chặn hoàn toàn tương tác với nền và hỗ trợ các trạng thái collapsed và expanded. Hiểu các loại và hành vi của Sheet là cần thiết để xây dựng điều hướng thuận tiện trong các ứng dụng di động.
Những điểm chính
Sheet là một thành phần UI ở cấp độ bề mặt trượt lên từ cuối màn hình và hiển thị nội dung hoặc hành động bổ sung mà không đưa người dùng rời khỏi màn hình hiện tại. Không giống như chuyển tiếp toàn màn hình, Sheet giữ nguyên ngữ cảnh: người dùng nhìn thấy màn hình nền và hiểu Sheet xuất hiện từ đâu.
Kiến trúc của Sheet dựa trên vùng chứa có chiều cao điều chỉnh được. Ở trạng thái tối thiểu (collapsed), chỉ một phần nội dung hiển thị — thường là tiêu đề hoặc một bảng nhỏ. Người dùng có thể kéo Sheet lên trên để mở rộng (expanded) hoặc vuốt xuống để đóng. Hành vi này giống như một tờ giấy vật lý được kéo ra từ dưới một chồng giấy — do đó có tên gọi Sheet.
Google trong hướng dẫn Material Design 3 (2024) nêu bật hai kịch bản chính để sử dụng Sheet: hiển thị các hành động bổ sung không vừa trên thanh công cụ chính và hiển thị biểu mẫu hoặc thông tin chi tiết mà không cần điều hướng đến màn hình riêng. Trên iOS, Apple đã thêm hỗ trợ Sheet ở cấp hệ thống từ iOS 15 qua UISheetPresentationController, xác nhận tính phổ quát của mẫu này.
Material Design định nghĩa ba loại Bottom Sheet, mỗi loại có hành vi và phạm vi ứng dụng riêng. Chọn đúng loại ảnh hưởng trực tiếp đến trải nghiệm người dùng và sự tuân thủ hướng dẫn nền tảng.
Bottom Sheet tiêu chuẩn là thành phần không modal: người dùng có thể tương tác với màn hình nền mà không cần đóng Sheet. Ví dụ: khi duyệt danh sách sản phẩm ở nền, người dùng thấy bộ lọc trong Bottom Sheet và có thể thay đổi chúng mà không cần đóng bảng. Sheet điều chỉnh chiều cao theo nội dung — từ 30% đến 90% màn hình.
Bottom Sheet tiêu chuẩn không chặn nền và cho phép tương tác với nội dung chính. Đây là điểm khác biệt chính so với Sheet modal, yêu cầu hành động bắt buộc để tiếp tục. Sử dụng Sheet tiêu chuẩn khi thông tin bổ sung không quan trọng đối với kịch bản chính.
Bottom Sheet modal chặn tương tác với màn hình nền cho đến khi người dùng thực hiện hành động bên trong Sheet. Sheet này luôn hiển thị ở trạng thái mở rộng và yêu cầu đóng rõ ràng — qua nút, hành động hoặc vuốt xuống. Material Design khuyên dùng Sheet modal cho biểu mẫu đăng nhập, xác nhận và cài đặt quan trọng.
Trên Android, Bottom Sheet modal được triển khai qua BottomSheetDialogFragment, tự động chặn nền. Trên iOS, hành vi tương tự được cung cấp bởi biến thể modal của UISheetPresentationController với tham số .mediumDetent. Sheet modal chỉ nên được sử dụng khi ngữ cảnh yêu cầu sự chú ý của người dùng.
Bottom Sheet mở rộng kết hợp các thuộc tính của tiêu chuẩn và modal: nó bắt đầu như không modal ở trạng thái collapsed, nhưng khi kéo lên sẽ trở thành modal. Trong thực tế, điều này có nghĩa là người dùng có thể xem lướt qua nội dung trước, sau đó quyết định — mở rộng Sheet để nghiên cứu chi tiết hoặc đóng nó.
Mẫu này đặc biệt phổ biến trong bản đồ và ứng dụng điều hướng, nơi bảng dưới cùng hiển thị thông tin ngắn gọn về một điểm trên tuyến đường và khi vuốt lên sẽ mở rộng với chi tiết. Google Maps sử dụng chính Sheet mở rộng này để hiển thị thông tin về địa điểm và tuyến đường.
| Loại Sheet | Chặn nền | Trạng thái ban đầu | Ví dụ |
|---|---|---|---|
| Tiêu chuẩn | Không | Collapsed | Bộ lọc trong danh mục |
| Modal | Có | Expanded | Biểu mẫu đăng nhập |
| Mở rộng | Một phần | Collapsed | Thẻ địa điểm |
Android SDK cung cấp nhiều API để triển khai Bottom Sheet, từ cách tiếp cận cổ điển dựa trên View đến Jetpack Compose hiện đại. Thư viện Material Components cho Android bao gồm các triển khai có sẵn của BottomSheetDialogFragment và BottomSheetBehavior.
BottomSheetBehavior là một lớp từ Material Components được gắn vào bất kỳ View nào và kiểm soát vị trí của nó trên màn hình. Nhà phát triển đặt ba trạng thái: STATE_COLLAPSED, STATE_EXPANDED và STATE_HIDDEN. Behavior tự động xử lý cử chỉ kéo và hoạt ảnh.
val sheet = findViewById<View>(R.id.bottom_sheet)
val behavior = BottomSheetBehavior.from(sheet)
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
behavior.peekHeight = 200
Jetpack Compose cung cấp API khai báo hơn qua thành phần ModalBottomSheet từ Material 3. Không giống như cách tiếp cận dựa trên View, trong Compose, Bottom Sheet là một hàm composable chấp nhận trạng thái và nội dung. Sheet tự động tạo hoạt ảnh cho việc xuất hiện, ẩn đi và thay đổi chiều cao khi kéo.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FilterSheet(onDismiss: () -> Unit) {
ModalBottomSheet(onDismissRequest = onDismiss) {
Text("Bộ lọc")
Button(onClick = onDismiss) { Text("Áp dụng") }
}
}
BottomSheetDialogFragment là một DialogFragment chuyên dụng hiển thị dưới dạng Bottom Sheet. Nó tự động xử lý tính modal, vòng đời và thay đổi cấu hình. Nhà phát triển chỉ cần ghi đè onCreateView và trả về bố cục Sheet. Theo tài liệu của Google (Android Developers, 2024), BottomSheetDialogFragment là cách tiếp cận được khuyến nghị cho Bottom Sheets modal trong Android cổ điển.
Apple đã giới thiệu hỗ trợ Sheet ở cấp hệ thống từ iOS 15 qua UISheetPresentationController. Trước đó, các nhà phát triển triển khai Bottom Sheet thủ công qua chuyển tiếp tùy chỉnh hoặc thư viện bên thứ ba. Sheet gốc của Apple hỗ trợ detents — các mức mở rộng được xác định trước.
UISheetPresentationController là bộ điều khiển trình bày tích hợp hiển thị View Controller dưới dạng Sheet. Nhà phát triển chỉ định một mảng detents — các giá trị chiều cao mà Sheet có thể dừng lại. iOS 16 đã thêm detents tùy chỉnh với chiều cao bất kỳ. Apple khuyến nghị sử dụng detents medium (.medium) và large (.large) làm chính.
let viewController = MySheetViewController()
if let sheet = viewController.sheetPresentationController {
sheet.detents = [.medium, .large]
sheet.prefersGrabberVisible = true
sheet.preferredCornerRadius = 16
}
present(viewController, animated: true)
SwiftUI cung cấp bổ từ .sheet, liên kết việc hiển thị Sheet với trạng thái. Khi một biến published trở thành true, SwiftUI tự động hiển thị Sheet. SwiftUI cũng hỗ trợ detents qua bổ từ .presentationDetents, được thêm vào trong iOS 16.
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("Hiển thị Sheet") { showSheet = true }
.sheet(isPresented: $showSheet) {
FilterView()
.presentationDetents([.medium, .large])
}
}
}
Các framework đa nền tảng cũng hỗ trợ Bottom Sheet, điều chỉnh hành vi theo nền tảng mục tiêu. Flutter và React Native cung cấp các triển khai tích hợp và tùy chỉnh với các mức độ linh hoạt khác nhau.
Flutter SDK chứa hai phương thức để hiển thị Bottom Sheet: showBottomSheet (tiêu chuẩn) và showModalBottomSheet (modal). Material Design trong Flutter tuân theo các nguyên tắc giống như trong Android — Sheet xuất hiện từ dưới lên, hỗ trợ kéo và có chiều cao điều chỉnh được. Đối với hành vi mở rộng với detents, DraggableScrollableSheet được sử dụng.
Scaffold.of(context).showBottomSheet((context) {
return Container(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text("Nội dung Sheet"),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("Đóng")
)
]
)
);
})
React Native không có thành phần Bottom Sheet tích hợp trong lõi của nó, vì vậy các nhà phát triển sử dụng thư viện bên thứ ba. Phổ biến nhất là @gorhom/bottom-sheet (hơn 7.000 sao trên GitHub, 2024). Nó cung cấp Bottom Sheet điều khiển bằng cử chỉ với hỗ trợ snap points, hoạt ảnh và tiêu đề cố định. Thư viện được xây dựng trên Reanimated 2 và Gesture Handler để đạt hiệu suất 60 FPS.
Sử dụng đúng cách Bottom Sheet yêu cầu tuân thủ hướng dẫn nền tảng và hiểu các kịch bản mà Sheet phù hợp. Hãy xem xét các khuyến nghị chính và lỗi thường gặp khi thiết kế Sheet.
Bottom Sheet tối ưu cho các hành động bổ sung cho nội dung chính trên màn hình. Bộ lọc, sắp xếp, chọn tùy chọn, thông tin ngắn gọn về một mục — các kịch bản điển hình. Material Design khuyên dùng Bottom Sheet cho các công cụ không nên chiếm toàn bộ màn hình nhưng cần nhiều không gian hơn Action Sheet hoặc Popup Menu.
Không sử dụng Bottom Sheet cho các cảnh báo quan trọng hoặc lỗi — cửa sổ hộp thoại phù hợp hơn cho việc này. Tránh các Sheet có nhiều trường nhập liệu yêu cầu cuộn: người dùng gặp khó khăn khi tiếp cận bàn phím và mất ngữ cảnh. Nếu Sheet chứa hơn bảy mục hành động, hãy cân nhắc một màn hình riêng thay vì Sheet.
Một lỗi điển hình là đặt peekHeight (chiều cao ở trạng thái thu gọn) lớn hơn 40% màn hình. Người dùng không biết liệu họ đang nhìn thấy toàn bộ Sheet hay có thể mở rộng nó. Material Design khuyến nghị peekHeight trong khoảng 15-30% chiều cao màn hình để để lại một phần nội dung đáng kể bị ẩn và khuyến khích kéo.
Trên iOS, người dùng mong đợi có thể đóng Sheet bằng cách vuốt xuống từ bất kỳ vị trí nào. Nếu bạn vô hiệu hóa cử chỉ này (qua UISheetPresentationController.prefersEdgeAttachedInCompactHeight), người dùng sẽ cảm thấy thất vọng khi cố gắng đóng Sheet theo cách quen thuộc. Hướng dẫn Giao diện Người dùng của Apple (2024) nhấn mạnh rằng vuốt để đóng là kỳ vọng cơ bản của người dùng iOS.
Câu hỏi thường gặp
Bottom Sheet không chặn hoàn toàn nền và hỗ trợ kéo, trong khi cửa sổ hộp thoại là modal và yêu cầu hành động bắt buộc. Bottom Sheet phù hợp hơn cho các tùy chọn bổ sung, hộp thoại cho các xác nhận quan trọng.
Có, nhưng cần cấu hình adjustResize hoặc adjustPan trong tệp kê khai Android. Trên iOS, bàn phím tự động nâng Sheet lên. Flutter và React Native yêu cầu xử lý thủ công qua MediaQuery để định vị chính xác.
Khuyến nghị không quá 5-7 mục trong Sheet tiêu chuẩn. Nếu có nhiều nội dung hơn, hãy sử dụng cuộn hoặc chia thành danh mục. Material Design khuyên không vượt quá 90% chiều cao màn hình ở trạng thái mở rộng.
Đối với Sheet modal, đặt setCancelable(true) trên Android hoặc isModalInPresentation = false trên iOS. Trong Jetpack Compose, onDismissRequest tự động xử lý chạm vào nền. Trong SwiftUI, vuốt xuống là hành vi mặc định.
Có, tất cả các triển khai gốc đều hỗ trợ VoiceOver và TalkBack. Đảm bảo rằng FocusManager di chuyển tiêu điểm vào Sheet khi mở và trả lại khi đóng. Các triển khai tùy chỉnh yêu cầu cấu hình khả năng tiếp cận thủ công.
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