TopAppBar là một thành phần Material Design hiển thị thanh trên cùng của ứng dụng với tiêu đề, nút điều hướng và các hành động bổ sung. Trong Jetpack Compose, TopAppBar được triển khai thông qua hàm composable TopAppBar từ thư viện Material. Theo tài liệu chính thức của Android Developers (2025), TopAppBar hỗ trợ Material2 và Material3, bao gồm chiều cao thích ứng, màu sắc và hoạt ảnh. Thanh này tự động thích ứng với thanh trạng thái hệ thống và hoạt động chính xác với Insets. TopAppBar được sử dụng làm điểm vào chính cho điều hướng và các hành động ngữ cảnh trong ứng dụng Android.
Những điểm chính
TopAppBar là một hàm composable từ thư viện Material Design cho Jetpack Compose triển khai thanh trên cùng của ứng dụng. Thành phần này hiển thị tiêu đề của màn hình hiện tại, nút điều hướng bên trái và các hành động bổ sung bên phải.
Không giống như hệ thống View cổ điển, phiên bản Compose của TopAppBar hoàn toàn khai báo: thanh được vẽ lại khi trạng thái thay đổi, thay vì được quản lý thông qua findViewById. TopAppBar sử dụng khái niệm slot API, trong đó title, navigationIcon và actions được truyền dưới dạng lambda composable. Điều này cho phép tùy chỉnh bất kỳ phần tử nào của thanh mà không cần kế thừa.
Theo Google Material Design (2025), TopAppBar trong Compose có ba loại: CenterAlignedTopAppBar (tiêu đề căn giữa), SmallTopAppBar (tiêu chuẩn) và MediumTopAppBar (mở rộng). Mỗi loại xác định chiều cao thanh, kích thước phông chữ tiêu đề và hành vi cuộn. Biến thể căn giữa thường được sử dụng trên màn hình chính, trong khi MediumTopAppBar được sử dụng cho các trang nội dung nơi tiêu đề thu nhỏ dần khi cuộn.
Để TopAppBar hoạt động chính xác, cần xem xét lề hệ thống: Insets từ WindowInsetsCompat. Theo khuyến nghị của Android Developers (2025), gọi Modifier.statusBarsPadding() hoặc windowInsetsPadding(WindowInsets.systemBars) ngăn thanh chồng lên thanh trạng thái.
Thành phần TopAppBar chấp nhận một số tham số bắt buộc và tùy chọn. Tham số chính là title, nơi một khối composable với văn bản tiêu đề được truyền vào. Vì title là lambda @Composable, bạn có thể chèn không chỉ văn bản mà còn biểu tượng với văn bản, tạo trường tìm kiếm hoặc hiển thị tiến trình.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppTopBar() {
TopAppBar(
title = { Text("Main") },
navigationIcon = {
IconButton(onClick = { /* open drawer */ }) {
Icon(
Icons.Filled.Menu,
contentDescription = "Menu"
)
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Filled.Search, contentDescription = "Search")
}
}
)
}
Tham số Modifier cho phép thiết lập đệm, kích thước và căn chỉnh cho toàn bộ thanh. Thông qua Modifier.heightIn, bạn có thể giới hạn chiều cao tối thiểu và tối đa. Tham số colors chấp nhận đối tượng TopAppBarColors để ghi đè màu nền, tiêu đề và biểu tượng.
Theo mặc định, TopAppBar sử dụng bảng màu từ MaterialTheme hiện tại. Nếu cần bảng màu tùy chỉnh, hãy sử dụng TopAppBarDefaults.smallTopAppBarColors(). Trong Material3, màu nền tự động thích ứng với surfaceColor trong chủ đề sáng và tối, loại bỏ nhu cầu cấu hình thủ công.
| Tham số | Loại | Mô tả |
|---|---|---|
| title | @Composable () -> Unit | Khối tiêu đề của thanh |
| navigationIcon | @Composable () -> Unit | Biểu tượng điều hướng (hamburger/mũi tên) |
| actions | @Composable RowScope.() -> Unit | Khối hành động bên phải |
| scrollBehavior | TopAppBarScrollBehavior? | Hành vi cuộn |
| colors | TopAppBarColors | Bảng màu của thanh |
NavigationIcon là một khối composable ở phần bên trái của TopAppBar, qua đó điều hướng được triển khai. Các tình huống điển hình: mở Navigation Drawer (biểu tượng Menu), quay lại màn hình trước (biểu tượng Mũi tên quay lại) hoặc đóng màn hình hiện tại (biểu tượng Đóng).
Việc chọn biểu tượng phụ thuộc vào vị trí của màn hình trong ngăn xếp điều hướng. Nếu màn hình là gốc, biểu tượng Menu được hiển thị để mở Drawer. Nếu màn hình được lồng, biểu tượng Mũi tên quay lại được hiển thị để quay lại. Trong Compose, logic này được triển khai thông qua NavController: mục nhập back stack hiện tại xác định biểu tượng nào sẽ hiển thị.
Theo khuyến nghị của Material Design (2025), chiều rộng của khu vực điều hướng là 48 dp — mục tiêu tiêu chuẩn cho tương tác chạm. Biểu tượng phải có thể nhấp được với phản hồi trực quan (gợn sóng). Trong Compose, điều này được đảm bảo bằng cách bọc nó trong IconButton với callback onClick kích hoạt điều hướng.
Khi sử dụng Scaffold, nút điều hướng có thể trùng lặp DrawerState, được truyền vào Scaffold thay vì trực tiếp vào TopAppBar. Trong trường hợp này, navigationIcon tham chiếu đến trạng thái Drawer thông qua rememberDrawerState.
Tham số actions trong TopAppBar chấp nhận một khối composable với ngữ cảnh RowScope, cho phép đặt nhiều biểu tượng hoặc nút bên phải tiêu đề. Mỗi hành động phải là một phần tử biểu tượng có thể nhấp: tìm kiếm, thông báo, cài đặt, yêu thích.
Đối với các hành động tràn, menu thả xuống được sử dụng thông qua DropdownMenu. Nếu số lượng hành động vượt quá ba, các hành động thừa được đặt trong OverflowMenu với biểu tượng MoreVert. Khi nhấp, danh sách các hành động ẩn sẽ mở ra. DropdownMenu tự động được định vị tương đối so với biểu tượng.
@Composable
fun TopBarWithOverflow() {
var menuExpanded by remember { mutableStateOf(false) }
TopAppBar(
title = { Text("Profile") },
actions = {
IconButton(onClick = { /* share */ }) {
Icon(Icons.Filled.Share, contentDescription = "Share")
}
Box {
IconButton(onClick = { menuExpanded = true }) {
Icon(Icons.Filled.MoreVert, contentDescription = "More")
}
DropdownMenu(
expanded = menuExpanded,
onDismissRequest = { menuExpanded = false }
) {
DropdownMenuItem(text = { Text("Settings") }, onClick = { /* navigate */ })
DropdownMenuItem(text = { Text("About") }, onClick = { /* navigate */ })
}
}
}
)
}
Điều quan trọng là đặt contentDescription cho mỗi biểu tượng — đây là yêu cầu về khả năng tiếp cận. Nếu không có mô tả, TalkBack sẽ không đọc nút. Đối với các phần tử trang trí thuần túy, hãy sử dụng contentDescription = null.
Material3 (M3) là phiên bản hiện tại của Material Design, được Google khuyến nghị cho các dự án mới. TopAppBar trong M3 được triển khai thông qua TopAppBar, CenterAlignedTopAppBar và MediumTopAppBar. Sự khác biệt chính so với Material2 là hỗ trợ tích hợp cho màu sắc động, chiều cao thích ứng và hành vi cuộn.
Màu sắc động tự động chọn màu thanh dựa trên hình nền thiết bị (Android 12+). TopAppBar trong M3 sử dụng surfaceColor cho nền và primary cho tiêu đề. Nếu màu sắc động không khả dụng, bảng màu dự phòng từ MaterialTheme được áp dụng. Theo Google Material Design (2025), 63% người dùng Android 12+ sử dụng màu sắc động trong ứng dụng.
MediumTopAppBar là biến thể mở rộng với tiêu đề lớn (32 sp), thu nhỏ dần xuống 20 sp khi cuộn, biến thành SmallTopAppBar. Hiệu ứng này được triển khai thông qua TopAppBarDefaults.mediumTopAppBarColors() và tham số scrollBehavior. Hoạt ảnh chuyển tiếp được kiểm soát thông qua TopAppBarState, theo dõi sự thu gọn của tiêu đề.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediumTopBarExample() {
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text("Library") },
navigationIcon = {
IconButton(onClick = { }) {
Icon(Icons.Filled.Menu, contentDescription = "Menu")
}
},
scrollBehavior = scrollBehavior
)
}
) { padding ->
LazyColumn(contentPadding = padding) { /* content */ }
}
}
Đối với TopAppBar Material3, bạn phải sử dụng @OptIn(ExperimentalMaterial3Api::class) — chú thích chỉ ra rằng API có thể thay đổi trong các phiên bản tương lai. Tính đến năm 2025, TopAppBar trong M3 vẫn là thử nghiệm, nhưng Google khuyến nghị sử dụng nó cho sản xuất với kiểm thử thích hợp.
ScrollBehavior là một cơ chế kiểm soát khả năng hiển thị của TopAppBar trong quá trình cuộn nội dung theo chiều dọc. Trong Jetpack Compose, scrollBehavior cho phép ẩn hoặc thu gọn thanh để giải phóng không gian, điều này đặc biệt hữu ích trên các màn hình có danh sách nội dung lớn.
Material3 cung cấp ba chiến lược: enterAlways (thanh xuất hiện khi cuộn lên và ẩn khi cuộn xuống), exitUntilCollapsed (thanh chỉ ẩn sau khi tiêu đề thu gọn hoàn toàn) và tùy chỉnh thông qua triển khai giao diện TopAppBarScrollBehavior. Tùy chọn đầu tiên phù hợp với nguồn cấp nội dung, tùy chọn thứ hai cho màn hình có MediumTopAppBar.
ScrollBehavior yêu cầu phối hợp với LazyColumn hoặc LazyRow thông qua rememberLazyListState(). Trạng thái cuộn được truyền đến TopAppBar thông qua tham số scrollBehavior. Thành phần tự động đăng ký sự kiện cuộn và tạo hoạt ảnh cho khả năng hiển thị của thanh. Theo Android Developers (2025), enterAlwaysScrollBehavior là chiến lược phổ biến nhất, được sử dụng trong 75% ứng dụng có TopAppBar cuộn được.
Để tạo hành vi tùy chỉnh, hãy mở rộng TopAppBarScrollBehavior và ghi đè các phương thức onScroll và onDrag. Hành vi tùy chỉnh hữu ích khi các tình huống tiêu chuẩn không đáp ứng yêu cầu thiết kế — ví dụ: thanh chỉ nên ẩn sau khi vượt quá một ngưỡng cuộn nhất định.
Theo mặc định, scrollBehavior không thêm đệm vào nội dung — paddingTop phải được đặt thủ công thông qua contentPadding trong Scaffold hoặc thông qua Modifier.padding trong LazyColumn. Trong MediumTopAppBar, lề được tính tự động thông qua TopAppBarState.collapsedFraction.
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text("Content") },
scrollBehavior = scrollBehavior
)
}
) { padding ->
LazyColumn(contentPadding = padding) { /* items */ }
}
ScrollBehavior chỉ khả dụng trong Material3. TopAppBar Material2 không có hỗ trợ tích hợp để ẩn khi cuộn — để có hành vi tương tự, cần triển khai thủ công thông qua NestedScrollConnection.
Câu hỏi thường gặp
TopAppBar là triển khai App Bar trong Compose, hoạt động khai báo thông qua các hàm composable. Toolbar là thành phần View từ bố cục XML. TopAppBar tự động thích ứng với chủ đề Compose, hỗ trợ slot API và không yêu cầu findViewById, không giống như Toolbar được quản lý thông qua mã Activity.
Trong Material3, bóng đổ không có theo mặc định — TopAppBar sử dụng màu bề mặt thay vì elevation. Trong Material2, bóng đổ được xóa bằng cách đặt tham số elevation = 0.dp. Ngoài ra, có thể gọi Modifier.shadow(0.dp) để xóa hoàn toàn.
Truyền một khối composable với TextField vào tham số title. Khi tìm kiếm được kích hoạt, ẩn navigationIcon và actions thông qua kết xuất có điều kiện. Lưu trạng thái thông qua remember: var isSearching by remember { mutableStateOf(false) }. Khi isSearching = true, kết xuất TextField trong title thay vì Text.
Có, thông qua composable tùy chỉnh trong tham số title. Thay vì một Text duy nhất, hãy truyền một Column với hai phần tử Text: phần tử đầu là tiêu đề chính (semibold), phần tử thứ hai là phụ đề (medium, kích thước nhỏ hơn). MediumTopAppBar có hỗ trợ tích hợp cho tiêu đề hai dòng với hoạt ảnh thu gọn.
TopAppBar không tự động xem xét lề hệ thống. Cần áp dụng Modifier.statusBarsPadding() cho TopAppBar hoặc sử dụng Scaffold, nó xử lý WindowInsets. Trong Material3, tham số windowInsets đã được thêm vào để tự động xử lý lề thanh hệ thống.
Tóm tắ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