Drawer (Navigation Drawer) là một bảng tương tác trượt ra từ mép trái (hoặc phải) màn hình và hiển thị các liên kết điều hướng. Trên Android, nó được triển khai qua DrawerLayout, trên iOS — qua các giải pháp tùy chỉnh như SideMenu hoặc UISplitViewController tiêu chuẩn trên iPad. Đọc thêm về thông số kỹ thuật trong tài liệu Material Design 3.
Những điểm chính
Drawer (Navigation Drawer) là một phần tử điều hướng dạng bảng trượt ra từ mép trái màn hình bằng cử chỉ vuốt hoặc chạm vào biểu tượng hamburger (ba đường kẻ ngang). Drawer chứa các liên kết điều hướng, tiêu đề và các thành phần tùy chọn: ảnh đại diện người dùng, huy hiệu thông báo, dấu phân cách. Bảng có thể phủ lên nội dung (Modal) hoặc đẩy nó đi (Standard).
Material Design 3 (2026) định nghĩa Navigation Drawer là một thành phần cho ứng dụng có 6+ mục điều hướng. Không giống như Bottom Navigation, Drawer không chiếm không gian màn hình cố định và chỉ hiển thị khi người dùng yêu cầu. Điều này giải phóng không gian cho nội dung nhưng yêu cầu thao tác bổ sung để mở. Google khuyến nghị Drawer cho ứng dụng có cấu trúc phân cấp phần sâu.
Nghiên cứu của UX Planet (2025) cho thấy: Drawer phù hợp cho ứng dụng có 5–15 phần, nhưng thời gian điều hướng cao hơn 40% so với Bottom Navigation. Người dùng bỏ lỡ các mục menu nằm dưới nếp gấp màn hình (cuộn). Do đó, các phần quan trọng nên ở đầu Drawer, và các phần ít quan trọng hơn (Giới thiệu, Cài đặt) ở cuối, được phân cách bằng dấu phân cách.
Modal Drawer trượt lên trên nội dung, làm mờ nền. Được sử dụng trên thiết bị di động nơi chiều rộng màn hình bị giới hạn. Sau khi chọn mục, Drawer tự động đóng lại. Standard Drawer (Permanent) là bảng cố định luôn hiển thị, đẩy nội dung đi. Được sử dụng trên máy tính bảng và máy tính để bàn có chiều rộng màn hình từ 900 dp. Material 3 cũng định nghĩa Rail Drawer — phiên bản nhỏ gọn cho máy tính bảng chỉ hiển thị biểu tượng.
| Loại | Hành vi | Cách dùng |
|---|---|---|
| Modal | Phủ nội dung, làm mờ nền | Điện thoại, điều hướng tạm thời |
| Standard | Đẩy nội dung, cố định | Máy tính bảng, máy tính (900+ dp) |
| Rail | Bảng bên nhỏ gọn với biểu tượng | Máy tính bảng, điều hướng thích ứng |
DrawerLayout là ViewGroup tiêu chuẩn trong Android triển khai menu bên trượt. DrawerLayout chứa hai thành phần con: thứ nhất — nội dung chính (FrameLayout với NavHostFragment), thứ hai — NavigationView với menu. DrawerLayout xử lý cử chỉ vuốt và đóng/mở bằng lập trình qua ActionBarDrawerToggle.
// Hoạt động với DrawerLayout và NavigationView
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
drawerLayout = binding.drawerLayout
val navView = binding.navView
val navController = findNavController(R.id.nav_host_fragment)
// Liên kết Drawer với Navigation Component
NavigationUI.setupActionBarWithNavController(
this, navController, drawerLayout
)
NavigationUI.setupWithNavController(navView, navController)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(
findNavController(R.id.nav_host_fragment),
drawerLayout
)
}
}
// XML: activity_main.xml
// <androidx.drawerlayout.widget.DrawerLayout
// android:id="@+id/drawerLayout"
// ...>
// <!-- Nội dung chính -->
// <FrameLayout android:id="@+id/nav_host_fragment"
// android:layout_width="match_parent"
// android:layout_height="match_parent" />
// <!-- Navigation Drawer -->
// <com.google.android.material.navigation.NavigationView
// android:id="@+id/navView"
// android:layout_width="wrap_content"
// android:layout_height="match_parent"
// android:layout_gravity="start"
// app:menu="@menu/nav_menu" />
// </androidx.drawerlayout.widget.DrawerLayout>NavigationView là thành phần Material Design cho nội dung Drawer. Nó hỗ trợ tiêu đề (headerLayout), mục menu (menu), phụ đề, hộp kiểm và công tắc. Thuộc tính app:menu trỏ đến menu XML với các mục điều hướng. NavigationUI tự động làm nổi bật mục đang hoạt động và đồng bộ trạng thái với NavController.
iOS không có thành phần "Drawer" tích hợp — Apple không khuyến nghị menu bên cho iPhone (HIG, 2026). Tuy nhiên, cho iPad, UISplitViewController với bảng chính và phụ được sử dụng. Cho iPhone, menu bên được triển khai qua thư viện bên thứ ba (SideMenu, SwiftUI-side-menu) hoặc giải pháp tùy chỉnh với độ lệch nội dung. Trong SwiftUI, menu bên được tạo qua ZStack với hiệu ứng động độ lệch.
import SwiftUI
struct DrawerView<Content: View, Menu: View>: View {
let menuWidth: CGFloat = 280
@Binding var isOpen: Bool
@ViewBuilder let content: Content
@ViewBuilder let menu: Menu
var body: some View {
ZStack(alignment: .leading) {
content
.offset(x: isOpen ? menuWidth : 0)
.animation(.easeInOut, value: isOpen)
if isOpen {
menu
.frame(width: menuWidth)
.transition(.move(edge: .leading))
Color.black.opacity(0.3)
.ignoresSafeArea()
.onTapGesture { isOpen = false }
}
}
}
}
// Cách dùng
struct ContentView: View {
@State private var showDrawer = false
var body: some View {
DrawerView(isOpen: $showDrawer) {
NavigationStack {
HomeView()
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: { showDrawer.toggle() }) {
Image(systemName: "line.horizontal.3")
}
}
}
}
} menu: {
DrawerMenuView()
}
}
}Cho các dự án iOS sản xuất, thư viện SideMenu thường được sử dụng (GitHub, 8k+ sao). Nó cung cấp UIViewController sẵn sàng với hỗ trợ cử chỉ, làm mờ nền, chiều rộng tùy chỉnh và hiệu ứng động. SideMenu hỗ trợ menu trái và phải, nhiều cấp độ và tích hợp UIKit qua UINavigationController. Một giải pháp thay thế là UISplitViewController trên iPad (hệ thống, không có hiệu ứng động tùy chỉnh).
Drawer cho phép tùy chỉnh rộng rãi. Trong Android, NavigationView hỗ trợ headerLayout — bố cục tùy chỉnh được đặt phía trên các mục menu. Nó có thể chứa ảnh đại diện, tên người dùng, email và ảnh bìa. Các mục menu được nhóm qua <menu> với phụ đề, dấu phân cách và công tắc. Trên iOS, tùy chỉnh SideMenu bao gồm cài đặt màu nền, độ mờ, chiều rộng và bán kính góc.
// Tiêu đề tùy chỉnh cho NavigationView
val headerView = binding.navView.inflateHeaderView(R.layout.nav_header)
headerView.findViewById<ImageView>(R.id.iv_avatar)
.setImageResource(R.drawable.avatar)
headerView.findViewById<TextView>(R.id.tv_name)
.text = "John Doe"
// Cấu hình mục menu
val menuItem = binding.navView.menu.findItem(R.id.nav_notifications)
menuItem.isChecked = true
// Thêm huy hiệu
val badge = binding.navView.getOrCreateBadge(R.id.nav_notifications)
badge.number = 15
badge.isVisible = trueMaterial Design khuyến nghị cấu trúc Drawer sau: tiêu đề (tên, ảnh đại diện), các mục điều hướng chính (5–8), dấu phân cách, các mục phụ (Cài đặt, Trợ giúp), chân trang (Giới thiệu, phiên bản). Trong Material 3, NavigationView cũng hỗ trợ làm nổi bật mục đang hoạt động tùy chỉnh qua itemShape và itemBackground.
Drawer hiệu quả cho ứng dụng có 6+ phần, cài đặt và trang trợ giúp. Không phù hợp cho ứng dụng nơi truy cập nhanh vào các phần là quan trọng — trong những trường hợp đó, Bottom Navigation tốt hơn. Material Design khuyến nghị kết hợp Drawer với Bottom Navigation: điều hướng chính — Bottom (3–5 tab), bổ sung — Drawer (cài đặt, trợ giúp, giới thiệu).
Các lỗi phổ biến khi triển khai Drawer: menu quá tải (15+ mục không nhóm), ẩn các phần quan trọng dưới nếp gấp, thiếu biểu tượng (văn bản không có biểu tượng được quét chậm hơn 30%), hiệu ứng động có độ trễ (nên ≤ 200 ms). Các thực hành tốt nhất: tiêu đề với tên người dùng, biểu tượng cho mỗi mục, dấu phân cách giữa các nhóm, làm nổi bật phần đang hoạt động, hỗ trợ cử chỉ vuốt để mở.
Câu hỏi thường gặp
Drawer là menu bên ẩn được mở bằng cử chỉ, phù hợp cho 6+ phần và cấu trúc phân cấp sâu. Bottom Navigation là thanh dưới cùng luôn hiển thị cho 3–5 phần. Drawer tiết kiệm không gian màn hình nhưng yêu cầu thao tác bổ sung để mở, làm tăng thời gian điều hướng lên 40%.
SwiftUI không có Drawer tích hợp. Sử dụng ZStack với độ lệch nội dung và hiệu ứng động như trong ví dụ trên. Cho sản xuất, các thư viện được sử dụng: SideMenu (Swift Package) hoặc trình bao bọc tùy chỉnh quanh UISplitViewController. Trên iPad, sử dụng UISplitViewController với preferredDisplayMode .oneBesideSecondary.
Apple HIG (2026) tuyên bố: menu bên ẩn nội dung và vi phạm nguyên tắc thao tác trực tiếp. iOS khuyến nghị Tab Bar cho điều hướng. Drawer trên iPhone chỉ được sử dụng cho cài đặt và các hành động bổ sung, không phải cho điều hướng chính. Trên iPad, Drawer được thay thế bằng UISplitViewController, là tiêu chuẩn hệ thống.
Trong Android, DrawerLayout tự động xử lý vuốt từ mép trái. Trong iOS, Drawer tùy chỉnh yêu cầu UIPanGestureRecognizer hoặc Edge Pan Gesture (SwiftUI — .gesture với DragGesture). Quan trọng: cử chỉ vuốt phải xung đột với cử chỉ "Quay lại" của hệ thống — trên iOS, mép trái bị chiếm bởi cử chỉ hệ thống.
Có. Trong Android, chỉ định android:layout_gravity="end" cho NavigationView. Trên iOS, tạo menu với edge: .trailing. Drawer bên phải ít được sử dụng hơn — cho các tùy chọn bổ sung, bộ lọc hoặc trò chuyện. Điều hướng chính vẫn ở bên trái theo Material Design và mong đợi của người dù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