TopAppBar เป็นส่วนประกอบ Material Design ที่แสดงแถบด้านบนของแอปพลิเคชันพร้อมชื่อเรื่อง ปุ่มนำทาง และการดำเนินการเพิ่มเติม ใน Jetpack Compose TopAppBar ถูกนำมาใช้ผ่านฟังก์ชัน composable TopAppBar จากไลบรารี Material ตามเอกสารทางการของ Android Developers (2025) TopAppBar รองรับ Material2 และ Material3 รวมถึงความสูงแบบปรับได้ สี และแอนิเมชัน แถบจะปรับเข้ากับแถบสถานะของระบบโดยอัตโนมัติและทำงานอย่างถูกต้องกับ Insets TopAppBar ถูกใช้เป็นจุดเข้าหลักสำหรับการนำทางและการดำเนินการตามบริบทในแอปพลิเคชัน Android
ประเด็นสำคัญ
TopAppBar เป็นฟังก์ชัน composable จากไลบรารี Material Design สำหรับ Jetpack Compose ที่ใช้สร้างแถบด้านบนของแอปพลิเคชัน ส่วนประกอบนี้แสดงชื่อเรื่องของหน้าจอปัจจุบัน ปุ่มนำทางทางซ้าย และการดำเนินการเพิ่มเติมทางขวา
แตกต่างจากระบบ View แบบคลาสสิก เวอร์ชัน Compose ของ TopAppBar เป็นแบบประกาศอย่างสมบูรณ์: แถบจะถูกวาดใหม่เมื่อสถานะเปลี่ยนแปลง แทนที่จะจัดการผ่าน findViewById TopAppBar ใช้แนวคิด slot API ซึ่ง title, navigationIcon และ actions ถูกส่งเป็นแลมบ์ดา composable ซึ่งช่วยให้ปรับแต่งองค์ประกอบใดๆ ของแถบได้โดยไม่ต้องสืบทอด
ตาม Google Material Design (2025) TopAppBar ใน Compose มีสามประเภท: CenterAlignedTopAppBar (ชื่อเรื่องกึ่งกลาง), SmallTopAppBar (มาตรฐาน) และ MediumTopAppBar (ขยาย) แต่ละประเภทจะกำหนดความสูงของแถบ ขนาดฟอนต์ชื่อเรื่อง และพฤติกรรมการเลื่อน แบบกึ่งกลางถูกใช้บ่อยกว่าบนหน้าจอหลัก ในขณะที่ MediumTopAppBar ใช้สำหรับหน้าสารบัญที่ชื่อเรื่องจะค่อยๆ หดเล็กลงเมื่อเลื่อน
สำหรับการทำงานที่ถูกต้องของ TopAppBar จำเป็นต้องพิจารณาระยะขอบของระบบ: Insets จาก WindowInsetsCompat ตามคำแนะนำของ Android Developers (2025) การเรียก Modifier.statusBarsPadding() หรือ windowInsetsPadding(WindowInsets.systemBars) ป้องกันไม่ให้แถบทับซ้อนกับแถบสถานะ
ส่วนประกอบ TopAppBar รองรับพารามิเตอร์ที่จำเป็นและไม่จำเป็นหลายตัว พารามิเตอร์หลักคือ title ซึ่งส่งบล็อก composable พร้อมข้อความชื่อเรื่อง เนื่องจาก title เป็นแลมบ์ดา @Composable คุณสามารถแทรกได้ไม่เพียงแค่ข้อความ แต่ยังรวมถึงไอคอนพร้อมข้อความ สร้างช่องค้นหา หรือแสดงความคืบหน้า
@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")
}
}
)
}
พารามิเตอร์ Modifier ช่วยให้กำหนดระยะห่าง ขนาด และการจัดตำแหน่งสำหรับทั้งแถบ ผ่าน Modifier.heightIn คุณสามารถจำกัดความสูงต่ำสุดและสูงสุดได้ พารามิเตอร์ colors รับออบเจ็กต์ TopAppBarColors เพื่อแทนที่สีพื้นหลัง ชื่อเรื่อง และไอคอน
โดยค่าเริ่มต้น TopAppBar ใช้โทนสีจาก MaterialTheme ปัจจุบัน หากต้องการจานสีแบบกำหนดเอง ให้ใช้ TopAppBarDefaults.smallTopAppBarColors() ใน Material3 สีพื้นหลังจะปรับเข้ากับ surfaceColor โดยอัตโนมัติในธีมสว่างและมืด ซึ่งช่วยลดความจำเป็นในการกำหนดค่าด้วยตนเอง
| พารามิเตอร์ | ประเภท | คำอธิบาย |
|---|---|---|
| title | @Composable () -> Unit | บล็อกชื่อเรื่องของแถบ |
| navigationIcon | @Composable () -> Unit | ไอคอนนำทาง (แฮมเบอร์เกอร์/ลูกศร) |
| actions | @Composable RowScope.() -> Unit | บล็อกการดำเนินการทางขวา |
| scrollBehavior | TopAppBarScrollBehavior? | พฤติกรรมการเลื่อน |
| colors | TopAppBarColors | โทนสีของแถบ |
NavigationIcon คือบล็อก composable ทางด้านซ้ายของ TopAppBar ที่ใช้ในการนำทาง สถานการณ์ทั่วไป: เปิด Navigation Drawer (ไอคอนเมนู), กลับไปยังหน้าจอก่อนหน้า (ไอคอนลูกศรกลับ) หรือปิดหน้าจอปัจจุบัน (ไอคอนปิด)
การเลือกไอคอนขึ้นอยู่กับตำแหน่งของหน้าจอในสแต็กนำทาง หากหน้าจอเป็นราก จะแสดงไอคอน เมนู เพื่อเปิด Drawer หากหน้าจอซ้อนกัน จะแสดงไอคอน ลูกศรกลับ สำหรับการกลับไป ใน Compose ตรรกะนี้ถูกนำมาใช้ผ่าน NavController: รายการ back stack ปัจจุบันจะกำหนดว่าจะแสดงไอคอนใด
ตามคำแนะนำของ Material Design (2025) ความกว้างของพื้นที่นำทางคือ 48 dp ซึ่งเป็นเป้าหมายมาตรฐานสำหรับการโต้ตอบแบบสัมผัส ไอคอนควรคลิกได้พร้อมการตอบสนองทางภาพ (ripple) ใน Compose สิ่งนี้ได้รับการรับรองโดยการห่อใน IconButton พร้อมกับ callback onClick ที่เรียกใช้การนำทาง
เมื่อใช้ Scaffold ปุ่มนำทางอาจทำซ้ำ DrawerState ซึ่งถูกส่งไปยัง Scaffold แทนที่จะส่งไปยัง TopAppBar โดยตรง ในกรณีนี้ navigationIcon อ้างอิงถึงสถานะ Drawer ผ่าน rememberDrawerState
พารามิเตอร์ actions ใน TopAppBar รับบล็อก composable พร้อมบริบท RowScope ซึ่งช่วยให้วางไอคอนหรือปุ่มหลายรายการทางด้านขวาของชื่อเรื่อง แต่ละการดำเนินการควรเป็นองค์ประกอบไอคอนที่คลิกได้: ค้นหา, การแจ้งเตือน, การตั้งค่า, รายการโปรด
สำหรับการดำเนินการที่ล้นเกิน จะใช้เมนูแบบเลื่อนลงผ่าน DropdownMenu หากจำนวนการดำเนินการเกินสาม รายการที่เกินจะถูกวางใน OverflowMenu พร้อมไอคอน MoreVert เมื่อคลิก รายการของการดำเนินการที่ซ่อนอยู่จะเปิดขึ้น DropdownMenu จะถูกวางตำแหน่งโดยอัตโนมัติสัมพันธ์กับไอคอน
@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 */ })
}
}
}
)
}
สิ่งสำคัญคือต้องตั้งค่า contentDescription สำหรับแต่ละไอคอน ซึ่งเป็นข้อกำหนดด้านการเข้าถึง หากไม่มีคำอธิบาย TalkBack จะไม่ประกาศปุ่ม สำหรับองค์ประกอบที่ตกแต่งอย่างแท้จริง ให้ใช้ contentDescription = null
Material3 (M3) เป็นเวอร์ชันปัจจุบันของ Material Design ที่ Google แนะนำสำหรับโปรเจกต์ใหม่ TopAppBar ใน M3 ถูกนำมาใช้ผ่าน TopAppBar, CenterAlignedTopAppBar และ MediumTopAppBar ความแตกต่างหลักจาก Material2 คือการรองรับสีแบบไดนามิก ความสูงแบบปรับได้ และพฤติกรรมการเลื่อนในตัว
สีแบบไดนามิกจะเลือกสีของแถบโดยอัตโนมัติตามวอลเปเปอร์ของอุปกรณ์ (Android 12+) TopAppBar ใน M3 ใช้ surfaceColor สำหรับพื้นหลังและ primary สำหรับชื่อเรื่อง หากไม่สามารถใช้สีแบบไดนามิกได้ จะใช้จานสีสำรองจาก MaterialTheme ตาม Google Material Design (2025) 63% ของผู้ใช้ Android 12+ ใช้สีแบบไดนามิกในแอปพลิเคชัน
MediumTopAppBar เป็นรูปแบบขยายที่มีชื่อเรื่องขนาดใหญ่ (32 sp) ซึ่งจะค่อยๆ หดเล็กลงเป็น 20 sp เมื่อเลื่อน กลายเป็น SmallTopAppBar เอฟเฟกต์นี้ถูกนำมาใช้ผ่าน TopAppBarDefaults.mediumTopAppBarColors() และพารามิเตอร์ scrollBehavior แอนิเมชันการเปลี่ยนผ่านถูกควบคุมผ่าน TopAppBarState ซึ่งติดตามการหดตัวของชื่อเรื่อง
@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 */ }
}
}
สำหรับ TopAppBar ของ Material3 ต้องใช้ @OptIn(ExperimentalMaterial3Api::class) — คำอธิบายประกอบระบุว่า API อาจเปลี่ยนแปลงในเวอร์ชันในอนาคต ณ ปี 2025 TopAppBar ใน M3 ยังคงเป็นการทดลอง แต่ Google แนะนำให้ใช้สำหรับการผลิตพร้อมการทดสอบที่เหมาะสม
ScrollBehavior เป็นกลไกที่ควบคุมการมองเห็นของ TopAppBar ในระหว่างการเลื่อนเนื้อหาแนวตั้ง ใน Jetpack Compose scrollBehavior ช่วยให้ซ่อนหรือย่อแถบเพื่อเพิ่มพื้นที่ว่าง ซึ่งมีประโยชน์อย่างยิ่งบนหน้าจอที่มีรายการเนื้อหาจำนวนมาก
Material3 มีสามกลยุทธ์: enterAlways (แถบจะปรากฏเมื่อเลื่อนขึ้นและซ่อนเมื่อเลื่อนลง), exitUntilCollapsed (แถบจะซ่อนหลังจากชื่อเรื่องหดตัวเต็มที่เท่านั้น) และแบบกำหนดเองผ่านการใช้อินเทอร์เฟซ TopAppBarScrollBehavior ตัวเลือกแรกเหมาะสำหรับฟีดเนื้อหา ตัวเลือกที่สองสำหรับหน้าจอที่มี MediumTopAppBar
ScrollBehavior ต้องการการประสานงานกับ LazyColumn หรือ LazyRow ผ่าน rememberLazyListState() สถานะการเลื่อนจะถูกส่งไปยัง TopAppBar ผ่านพารามิเตอร์ scrollBehavior ส่วนประกอบจะสมัครรับเหตุการณ์การเลื่อนโดยอัตโนมัติและทำให้การมองเห็นของแถบเป็นแอนิเมชัน ตาม Android Developers (2025) enterAlwaysScrollBehavior เป็นกลยุทธ์ที่ได้รับความนิยมมากที่สุด ใช้ใน 75% ของแอปพลิเคชันที่มี TopAppBar แบบเลื่อนได้
ในการสร้างพฤติกรรมแบบกำหนดเอง ให้ขยาย TopAppBarScrollBehavior และแทนที่เมธอด onScroll และ onDrag พฤติกรรมแบบกำหนดเองมีประโยชน์เมื่อสถานการณ์มาตรฐานไม่ครอบคลุมความต้องการของการออกแบบ — ตัวอย่างเช่น แถบควรซ่อนหลังจากเกินเกณฑ์การเลื่อนที่กำหนดเท่านั้น
โดยค่าเริ่มต้น scrollBehavior จะไม่เพิ่มระยะห่างให้กับเนื้อหา — paddingTop ต้องตั้งค่าด้วยตนเองผ่าน contentPadding ใน Scaffold หรือผ่าน Modifier.padding ใน LazyColumn ใน MediumTopAppBar ระยะขอบจะถูกคำนวณโดยอัตโนมัติผ่าน TopAppBarState.collapsedFraction
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text("Content") },
scrollBehavior = scrollBehavior
)
}
) { padding ->
LazyColumn(contentPadding = padding) { /* items */ }
}
ScrollBehavior มีให้ใช้งานเฉพาะใน Material3 เท่านั้น TopAppBar ของ Material2 ไม่มีการรองรับการซ่อนเมื่อเลื่อนในตัว — สำหรับพฤติกรรมที่คล้ายกัน จำเป็นต้องนำไปใช้ด้วยตนเองผ่าน NestedScrollConnection
คำถามที่พบบ่อย
TopAppBar คือการนำเสนอ App Bar ใน Compose ที่ทำงานแบบประกาศผ่านฟังก์ชัน composable Toolbar เป็นส่วนประกอบ View จากเลย์เอาต์ XML TopAppBar ปรับให้เข้ากับธีม Compose โดยอัตโนมัติ รองรับ slot API และไม่ต้องใช้ findViewById ต่างจาก Toolbar ที่จัดการผ่านโค้ดของ Activity
ใน Material3 เงาจะไม่มีตามค่าเริ่มต้น — TopAppBar ใช้สีพื้นผิวแทน elevation ใน Material2 เงาจะถูกลบโดยการตั้งค่าพารามิเตอร์ elevation = 0.dp นอกจากนี้ สามารถเรียก Modifier.shadow(0.dp) เพื่อลบอย่างสมบูรณ์
ส่งบล็อก composable ที่มี TextField ไปยังพารามิเตอร์ title เมื่อเปิดใช้งานการค้นหา ให้ซ่อน navigationIcon และ actions ผ่านการแสดงผลแบบมีเงื่อนไข เก็บสถานะผ่าน remember: var isSearching by remember { mutableStateOf(false) } เมื่อ isSearching = true ให้แสดง TextField ใน title แทน Text
ใช่ ผ่าน composable แบบกำหนดเองในพารามิเตอร์ title แทนที่จะใช้ Text เดียว ให้ส่ง Column ที่มี Text สองรายการ: รายการแรกคือชื่อเรื่องหลัก (semibold) รายการที่สองคือชื่อเรื่องย่อย (medium, ขนาดเล็กกว่า) MediumTopAppBar มีการรองรับชื่อเรื่องสองบรรทัดในตัวพร้อมแอนิเมชันการหดตัว
TopAppBar ไม่พิจารณาระยะขอบของระบบโดยอัตโนมัติ จำเป็นต้องใช้ Modifier.statusBarsPadding() กับ TopAppBar หรือใช้ Scaffold ซึ่งจัดการ WindowInsets ใน Material3 ได้เพิ่มพารามิเตอร์ windowInsets สำหรับการจัดการระยะขอบของแถบระบบโดยอัตโนมัติ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม