Scaffold เป็นฟังก์ชัน composable ใน Jetpack Compose ที่ implement โครงสร้างหน้าจอพื้นฐานตามข้อกำหนด Material Design Scaffold มี slots สำหรับ TopAppBar, BottomBar, FloatingActionButton, Drawer และ Snackbar ตาม Google Android Documentation, 2025, Scaffold เป็นองค์ประกอบที่จำเป็นสำหรับหน้าจอส่วนใหญ่ในแอปพลิเคชัน Compose เนื่องจากจัดการระยะขอบสำหรับส่วนประกอบระบบ Material Design
ประเด็นสำคัญ
Scaffold เป็นฟังก์ชัน composable ที่ implement โครงสร้างหน้าจอตามข้อกำหนด Material Design Scaffold ไม่ใช่คอนเทนเนอร์ในความหมายดั้งเดิม — เป็นตัวจัดการเลย์เอาต์ที่ประสานการวางตำแหน่งของส่วนประกอบ Material มาตรฐานหลายตัวบนหน้าจอ
Scaffold จัดการระยะขอบสำหรับ TopAppBar, BottomBar และ FloatingActionButton รวมถึงองค์ประกอบระบบ — แถบสถานะและแถบนำทาง ซึ่งรับประกันว่าเนื้อหาจะไม่ทับซ้อนกับองค์ประกอบระบบและเป็นไปตามแนวทาง Material Design
ตาม Material Design Guidelines, 2025, Scaffold ควรเป็นองค์ประกอบรากของทุกหน้าจอแอปพลิเคชัน มันแทนที่ CoordinatorLayout ที่เก่าจากระบบ View และมี API ที่ง่ายกว่าและเป็น declarative สำหรับสร้างเลย์เอาต์หน้าจอ
Scaffold รับพารามิเตอร์ modifier, scaffoldState, topBar, bottomBar, floatingActionButton, drawerContent, snackbarHost และ content พารามิเตอร์ content ได้รับ PaddingValues — ระยะขอบที่เนื้อหาหลักต้องคำนึงถึง
@Composable
fun BasicScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("หน้าแรก") }
)
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding)
) {
Text("เนื้อหาหลัก")
}
}
}
topBar เป็น slot สำหรับวางแถบด้านบนของแอปพลิเคชัน โดยทั่วไปคือ TopAppBar หรือ LargeTopAppBar Scaffold เพิ่มระยะขอบให้ innerPadding โดยอัตโนมัติเพื่อให้เนื้อหาไม่ทับซ้อนกับ topBar TopAppBar สามารถมีชื่อเรื่อง ไอคอนนำทาง และการดำเนินการ
bottomBar เป็น slot สำหรับแถบนำทางด้านล่าง รองรับ BottomNavigation, BottomAppBar หรือ NavigationBar Scaffold คำนึงถึงความสูงของ bottomBar เมื่อคำนวณ innerPadding สำหรับเนื้อหา ตาม Material Design Guidelines, 2025, bottomBar ควรใช้บนหน้าจอที่มี 3–5 จุดนำทาง
floatingActionButton เป็น slot สำหรับปุ่มดำเนินการลอย Scaffold วางตำแหน่ง FAB โดยอัตโนมัติตามข้อกำหนด Material Design — ที่มุมล่างขวาพร้อมระยะขอบที่ถูกต้อง floatingActionButtonPosition ช่วยให้ย้าย FAB ไปยังกึ่งกลางของขอบล่างของหน้าจอ
ในตัวอย่างนี้ Scaffold ใช้ slots หลักทั้งหมด: TopAppBar พร้อมชื่อเรื่อง, BottomBar ที่มีสามรายการนำทาง และ FloatingActionButton สำหรับการดำเนินการหลัก
@Composable
fun FullScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("แอป") },
navigationIcon = {
IconButton(onClick = {}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(
icon = { Icon(Icons.Default.Home, "หน้าแรก") },
label = { Text("Home") },
selected = true,
onClick = {}
)
NavigationBarItem(
icon = { Icon(Icons.Default.Search, "ค้นหา") },
label = { Text("Search") },
selected = false,
onClick = {}
)
}
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, "Add")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("เนื้อหาหน้าจอ")
}
}
}
ScaffoldState เป็นออบเจกต์สถานะของ Scaffold ที่รวม DrawerState และ SnackbarHostState DrawerState จัดการการเปิดและปิดเมนูด้านข้าง ในขณะที่ SnackbarHostState จัดการการแสดงและซ่อน Snackbar สถานะถูกสร้างขึ้นผ่าน rememberScaffoldState() และส่งต่อไปยังพารามิเตอร์ scaffoldState
DrawerState มีเมธอด open และ close สำหรับการควบคุม Drawer เชิงโปรแกรม สถานะของ Drawer สามารถเปิด ปิด หรือเปิดบางส่วนได้ drawerGesturesEnabled ช่วยให้ปิดใช้งานท่าปัดเพื่อเปิด Drawer โดยเหลือเพียงการเปิดเชิงโปรแกรมผ่านปุ่ม
SnackbarHostState จัดการ Snackbar — การแจ้งเตือนชั่วคราวที่ด้านล่างของหน้าจอ เมธอด showSnackbar แสดง Snackbar พร้อมข้อความและการดำเนินการเสริม ตาม Material Design Guidelines, 2025, Snackbar ควรใช้สำหรับข้อความสั้น ๆ ที่ไม่มีข้อมูลสำคัญวิกฤต
@Composable
fun ScaffoldWithDrawer() {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text("เมนู") },
navigationIcon = {
IconButton(onClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
drawerContent = {
Column(modifier = Modifier.padding(16.dp)) {
Text("รายการ 1")
Text("รายการ 2")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("เนื้อหา")
}
}
}
ตัวอย่างหน้าจอที่สมบูรณ์ด้วย Scaffold รวมถึง TopAppBar, BottomNavigation, FloatingActionButton และ Snackbar สำหรับแสดงการแจ้งเตือนเมื่อกด FAB ScaffoldState ถูกส่งไปยังส่วนประกอบทั้งหมดเพื่อประสานงานสถานะ
@Composable
fun MainScreen() {
val state = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = state,
topBar = {
TopAppBar(
title = { Text("IT Sectr") },
actions = {
IconButton(onClick = {}) {
Icon(Icons.Default.Notifications, "Notifications")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(icon = { Icon(Icons.Default.Home, "หน้าแรก") },
label = { Text("Home") }, selected = true, onClick = {})
NavigationBarItem(icon = { Icon(Icons.Default.Settings, "การตั้งค่า") },
label = { Text("Settings") }, selected = false, onClick = {})
}
},
floatingActionButton = {
FloatingActionButton(onClick = {
scope.launch {
state.snackbarHostState.showSnackbar("เสร็จ")
}
}) {
Icon(Icons.Default.Add, "Add")
}
}
) { padding ->
Box(
modifier = Modifier.padding(padding).fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("ยินดีต้อนรับ")
}
}
}
innerPadding คือ PaddingValues ที่ Scaffold ส่งไปยังบล็อก content ซึ่งมีระยะขอบที่จำเป็นเพื่อป้องกันเนื้อหาทับซ้อนกับ statusBar, navigationBar, topBar และ bottomBar การใช้ innerPadding เป็นสิ่งจำเป็นสำหรับการแสดงผลที่ถูกต้องบนอุปกรณ์ต่าง ๆ
Scaffold คำนวณ innerPadding โดยอัตโนมัติตามระยะขอบของระบบและความสูงของ slots ที่ติดตั้ง บนอุปกรณ์ที่มีกล้องแบบเกาะหรือรอยบากหน้าจอ Scaffold ปรับระยะขอบสำหรับแถบสถานะ บนอุปกรณ์รุ่นเก่าที่มีปุ่มจริง ระยะขอบด้านล่างอาจไม่มี
ตาม Android Developers, 2024, innerPadding ควรใช้กับคอนเทนเนอร์รากของเนื้อหาผ่าน Modifier.padding(innerPadding) หากเนื้อหาใช้คอนเทนเนอร์ที่เลื่อนได้ innerPadding จะถูกใช้ผ่าน Modifier.consumeWindowInsets เพื่อให้คีย์บอร์ดและท่าทางระบบทำงานถูกต้อง
คำถามที่พบบ่อย
Scaffold ไม่ใช่คอนเทนเนอร์ แต่เป็นตัวจัดการเลย์เอาต์ที่ควบคุม slots สำหรับ TopAppBar, BottomBar, FAB, Drawer และ Snackbar และจัดการระยะขอบสำหรับส่วนประกอบระบบโดยอัตโนมัติ Column และ Box จัดวางองค์ประกอบเท่านั้นโดยไม่คำนึงถึง Material Design
Scaffold แนะนำสำหรับหน้าจอที่ใช้ส่วนประกอบ Material Design บนหน้าจอที่ไม่มี TopAppBar, BottomBar หรือ FAB, Scaffold ไม่จำเป็น แต่ให้ระยะขอบระบบที่ถูกต้องผ่าน innerPadding ซึ่งมีประโยชน์แม้ไม่มี slots
ส่ง ScaffoldState ไปยังพารามิเตอร์ scaffoldState ของ Scaffold จากนั้นเรียก state.snackbarHostState.showSnackbar(“ข้อความ”) ภายใน coroutine Scaffold จะแสดง Snackbar ที่ด้านล่างของหน้าจอโดยอัตโนมัติ
ได้ Scaffold สร้างสถานะภายในโดยค่าเริ่มต้นหากไม่ส่ง scaffoldState อย่างไรก็ตาม หากต้องการควบคุม Drawer และ Snackbar เชิงโปรแกรม จำเป็นต้องสร้างและส่ง ScaffoldState ผ่าน rememberScaffoldState()
ใช้พารามิเตอร์ floatingActionButtonPosition ของ Scaffold โดยค่าเริ่มต้น FAB อยู่ที่มุมล่างขวา (FabPosition.End) ตั้งค่า FabPosition.Center เพื่อวาง FAB ไว้ที่กึ่งกลางของขอบล่างของหน้าจอ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม