Drawer — là gì, DrawerLayout và menu bên trong ứng dụng

Tác giả: IT Sectr Đã đăng: 2026-02-23 Thời gian đọc: 12 phút

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 là menu điều hướng bên trượt ra bằng cách vuốt hoặc chạm vào biểu tượng hamburger
  • DrawerLayout là vùng chứa tiêu chuẩn Android để triển khai menu trượt
  • SideMenu là thư viện iOS phổ biến cho menu bên có thể tùy chỉnh
  • Modal Drawer phủ lên nội dung, được dùng để tập trung vào điều hướng
  • Standard Drawer đẩy nội dung sang phải, để lại một phần hiển thị

Drawer là gì?

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.

Các loại Drawer: Modal và Standard

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ạiHành viCách dùng
ModalPhủ 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ố địnhMáy tính bảng, máy tính (900+ dp)
RailBảng bên nhỏ gọn với biểu tượngMáy tính bảng, điều hướng thích ứng

DrawerLayout trong Android

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.

kotlin
// 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.

Menu bên trong iOS

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.

swift
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).

Tùy chỉnh Drawer: tiêu đề, biểu tượng, phần

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.

kotlin
// 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 = true

Material 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.

Khi nào sử dụng Drawer: khuyến nghị UX

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ở.

  • 6+ phần — Drawer là hợp lý, ít hơn — sử dụng Bottom Navigation
  • Biểu tượng — bắt buộc cho mỗi mục, tăng tốc tìm kiếm trực quan
  • Nhóm — dấu phân cách giữa các mục chính và phụ
  • Tiêu đề — ảnh đại diện, tên và email để cá nhân hóa (ứng dụng xã hội)
  • Cử chỉ vuốt — bắt buộc để mở, được sao chép bằng nút hamburger

Câu hỏi thường gặp

Drawer khác Bottom Navigation như thế nào?

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%.

Làm thế nào để thêm Drawer trong SwiftUI?

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.

Tại sao Apple không khuyến nghị Drawer trên iPhone?

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.

Làm thế nào để xử lý cử chỉ vuốt cho Drawer?

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ó thể tạo Drawer ở bên phải khô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

  • Drawer — menu điều hướng bên cho 6+ phần, trượt ra bằng cách vuốt hoặc chạm hamburger
  • DrawerLayout (Android) — ViewGroup tiêu chuẩn với tích hợp Navigation Component qua NavigationUI
  • SideMenu (iOS) — thư viện phổ biến cho Drawer tùy chỉnh, vì Apple không cung cấp thành phần tích hợp
  • Modal vs Standard — Modal phủ nội dung (điện thoại), Standard đẩy nội dung (máy tính bảng 900+ dp)
  • Tùy chỉnh — tiêu đề với ảnh đại diện, nhóm mục, huy hiệu, làm nổi bật phần đang hoạt động
  • UX — Drawer chậm hơn 40% so với Bottom Navigation, nhưng cần thiết cho ứng dụng có cấu trúc phân cấp sâu
  • Material 3 — NavigationView hỗ trợ kiểu dáng, biểu tượng, huy hiệu và bố cục tiêu đề tùy chỉnh

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.

Thảo luận dự án

Đọc thêm