Jetpack Compose ช่วยให้การออกแบบและสร้าง UI ของแอปง่ายขึ้นมาก Compose เปลี่ยนสถานะเป็นองค์ประกอบ UI ผ่านสิ่งต่อไปนี้
- องค์ประกอบ
- เลย์เอาต์ขององค์ประกอบ
- การวาดองค์ประกอบ
เอกสารนี้มุ่งเน้นที่เลย์เอาต์ขององค์ประกอบ โดยจะอธิบายบล็อกการสร้างบางอย่างที่ Compose มีให้เพื่อช่วยคุณจัดวางองค์ประกอบ UI
เป้าหมายของเลย์เอาต์ใน Compose
การใช้งานระบบเลย์เอาต์ของ Jetpack Compose มีเป้าหมายหลัก 2 ประการ ได้แก่
- ประสิทธิภาพสูง
- ความสามารถในการเขียนเลย์เอาต์ที่กำหนดเองได้อย่างง่ายดาย
ข้อมูลเบื้องต้นเกี่ยวกับฟังก์ชันที่ประกอบกันได้
ฟังก์ชันที่ประกอบกันได้เป็นองค์ประกอบที่ใช้สร้างสรรค์พื้นฐานของ Compose ฟังก์ชันที่ประกอบกันได้
คือฟังก์ชันที่ปล่อย Unit ซึ่งอธิบายส่วนหนึ่งของ UI
ฟังก์ชันจะรับอินพุตบางอย่างและสร้างสิ่งที่แสดงบนหน้าจอ ดูข้อมูลเพิ่มเติมเกี่ยวกับ Composable ได้ในเอกสารประกอบโมเดลความคิดของ Compose
ฟังก์ชันที่ประกอบกันได้อาจปล่อยองค์ประกอบ UI หลายรายการ แต่หากคุณไม่ ให้คำแนะนำเกี่ยวกับวิธีจัดเรียง Compose อาจจัดเรียง องค์ประกอบในลักษณะที่คุณไม่ชอบ ตัวอย่างเช่น โค้ดนี้จะสร้างองค์ประกอบข้อความ 2 รายการ
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
หากไม่มีคำแนะนำเกี่ยวกับวิธีจัดเรียง Compose จะวางองค์ประกอบข้อความ ซ้อนกัน ทำให้ข้อความอ่านไม่ได้
Compose มีคอลเล็กชันเลย์เอาต์ที่พร้อมใช้งานเพื่อช่วยจัดเรียงองค์ประกอบ UI และช่วยให้คุณกำหนดเลย์เอาต์เฉพาะทางมากขึ้นได้ง่ายๆ
คอมโพเนนต์เลย์เอาต์มาตรฐาน
ในหลายๆ กรณี คุณสามารถใช้องค์ประกอบเลย์เอาต์มาตรฐานของ Compose ได้เลย
ใช้
Column
เพื่อวางรายการในแนวตั้งบนหน้าจอ
@Composable fun ArtistCardColumn() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
ในทำนองเดียวกัน ให้ใช้
Row
เพื่อวางรายการในแนวนอนบนหน้าจอ ทั้ง Column และ Row รองรับ
การกำหนดค่าการจัดแนวขององค์ประกอบที่ประกอบด้วย
@Composable fun ArtistCardRow(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
ใช้ Box เพื่อวางองค์ประกอบไว้เหนืออีกองค์ประกอบหนึ่ง Box ยังรองรับการกำหนดค่าการจัดแนวที่เฉพาะเจาะจงขององค์ประกอบที่มีอยู่ด้วย
@Composable fun ArtistAvatar(artist: Artist) { Box { Image(bitmap = artist.image, contentDescription = "Artist image") Icon(Icons.Filled.Check, contentDescription = "Check mark") } }
โดยส่วนใหญ่แล้ว คุณจะใช้ได้เพียงแค่บล็อกพื้นฐานเหล่านี้ คุณสามารถเขียนฟังก์ชันที่ประกอบกันได้ของคุณเองเพื่อรวมเลย์เอาต์เหล่านี้เป็นเลย์เอาต์ที่ซับซ้อนมากขึ้นซึ่งเหมาะกับแอปของคุณ
หากต้องการตั้งค่าตำแหน่งของเด็กภายใน Row ให้ตั้งค่าอาร์กิวเมนต์ horizontalArrangement และ
verticalAlignment สำหรับ Column ให้ตั้งค่าอาร์กิวเมนต์ verticalArrangement และ horizontalAlignment ดังนี้
@Composable fun ArtistCardArrangement(artist: Artist) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { /*...*/ } } }
โมเดลเลย์เอาต์
ในโมเดลเลย์เอาต์ ระบบจะวางเลย์เอาต์ของทรี UI ในการส่งผ่านครั้งเดียว ระบบจะขอให้แต่ละโหนด วัดขนาดของตัวเองก่อน จากนั้นจึงวัดโหนดลูกทั้งหมดแบบเรียกซ้ำ โดยส่ง ข้อจำกัดด้านขนาดลงไปในโครงสร้างไปยังโหนดลูก จากนั้นระบบจะกำหนดขนาดและ วางโหนดใบ โดยจะส่งขนาดที่กำหนดและวิธีการจัดวางกลับขึ้นไปตาม โครงสร้าง
กล่าวโดยย่อคือ ผู้ปกครองจะวัดก่อนบุตรหลาน แต่จะมีการกำหนดขนาดและวางไว้หลังบุตรหลาน
ลองพิจารณาฟังก์ชัน SearchResult ต่อไปนี้
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
ฟังก์ชันนี้จะสร้างแผนผัง UI ต่อไปนี้
SearchResult
Row
Image
Column
Text
Text
ในSearchResultตัวอย่าง เลย์เอาต์ของแผนผัง UI จะเป็นไปตามลำดับต่อไปนี้
- ระบบขอให้โหนดรูท
Rowวัด - โหนดรูท
Rowขอให้โหนดย่อยแรกImageทำการวัด Imageเป็นโหนดใบ (คือไม่มีโหนดลูก) จึงรายงานขนาด และแสดงวิธีการจัดวาง- โหนดรูท
Rowขอให้โหนดลูกที่ 2Columnทำการวัด - โหนด
Columnจะขอให้องค์ประกอบย่อยแรกTextทำการวัด - โหนด
Textแรกเป็นโหนดใบ (Leaf Node) จึงรายงานขนาดและแสดงผล วิธีการจัดวาง - โหนด
Columnจะขอให้โหนดลูกTextตัวที่ 2 ทำการวัด Textโหนดที่ 2 เป็นโหนดใบ (Leaf Node) จึงรายงานขนาดและแสดง วิธีการจัดวาง- ตอนนี้โหนด
Columnได้วัดขนาดและวางตำแหน่งขององค์ประกอบย่อยแล้ว จึงสามารถกำหนดขนาดและตำแหน่งของตัวเองได้ - ตอนนี้โหนดรูท
Rowได้วัดขนาดและวางตำแหน่งของโหนดลูกแล้ว จึงสามารถกำหนดขนาดและตำแหน่งของตัวเองได้
ประสิทธิภาพ
Compose มีประสิทธิภาพสูงด้วยการวัดเด็กเพียงครั้งเดียว การวัดผลแบบครั้งเดียวเหมาะสําหรับประสิทธิภาพ เนื่องจากช่วยให้ Compose จัดการโครงสร้าง UI ที่ซับซ้อนได้อย่างมีประสิทธิภาพ เช่น หากองค์ประกอบวัดองค์ประกอบย่อย 2 ครั้ง และองค์ประกอบย่อยนั้นวัดองค์ประกอบย่อยแต่ละรายการของตัวเอง 2 ครั้ง และอื่นๆ การพยายามจัดวาง UI ทั้งหมดเพียงครั้งเดียวจะต้องทำงานเป็นจำนวนมาก ซึ่งทำให้แอปทำงานได้ยาก
หากเลย์เอาต์ต้องมีการวัดหลายรายการด้วยเหตุผลบางประการ Compose มี ระบบพิเศษที่เรียกว่าการวัดค่าโดยธรรมชาติ อ่านเพิ่มเติมเกี่ยวกับฟีเจอร์นี้ได้ในการวัดค่าโดยธรรมชาติในเลย์เอาต์ Compose
เนื่องจากการวัดและการวางเป็นระยะย่อยที่แตกต่างกันของ Layout Pass การเปลี่ยนแปลงใดๆ ที่ส่งผลต่อการวางไอเทมเท่านั้น ไม่ใช่การวัด จึงสามารถดำเนินการแยกกันได้
การใช้ตัวแก้ไขในเลย์เอาต์
ดังที่ได้กล่าวไว้ในตัวปรับแต่ง Compose คุณสามารถใช้ตัวปรับแต่งเพื่อตกแต่งหรือเพิ่ม Composable ได้ ตัวแก้ไขเป็นสิ่งจำเป็น
สำหรับการปรับแต่งเลย์เอาต์ เช่น ในที่นี้เราจะเชื่อมโยงตัวแก้ไขหลายรายการ
เพื่อปรับแต่ง ArtistCard
@Composable fun ArtistCardModifiers( artist: Artist, onClick: () -> Unit ) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ } Spacer(Modifier.size(padding)) Card( elevation = CardDefaults.cardElevation(defaultElevation = 4.dp), ) { /*...*/ } } }
ในโค้ดด้านบน ให้สังเกตฟังก์ชันตัวแก้ไขต่างๆ ที่ใช้ร่วมกัน
clickableทำให้เกิดการตอบสนองที่ประกอบได้ต่อข้อมูลจากผู้ใช้และแสดงระลอกคลื่นpaddingจะเว้นที่ว่างรอบองค์ประกอบfillMaxWidthจะทำให้ Composable เติมความกว้างสูงสุดที่ได้รับจาก องค์ประกอบระดับบนsize()ระบุความกว้างและความสูงที่ต้องการขององค์ประกอบ
เลย์เอาต์ที่เลื่อนได้
ดูข้อมูลเพิ่มเติมเกี่ยวกับเลย์เอาต์ที่เลื่อนได้ในเอกสารประกอบเกี่ยวกับท่าทางสัมผัสในการเขียน
ดูรายการและรายการแบบเลซีได้ในเอกสารประกอบของรายการ Compose
การออกแบบที่ปรับเปลี่ยนตามอุปกรณ์
ควรออกแบบเลย์เอาต์โดยคำนึงถึงการวางแนวหน้าจอและขนาดรูปแบบของอุปกรณ์ต่างๆ Compose มีกลไกบางอย่างที่พร้อมใช้งานเพื่อช่วยปรับเลย์เอาต์ที่ประกอบได้ให้เข้ากับการกำหนดค่าหน้าจอต่างๆ
ข้อจำกัด
หากต้องการทราบข้อจำกัดที่มาจากองค์ประกอบระดับบนสุดและออกแบบเลย์เอาต์ตามนั้น คุณสามารถใช้ BoxWithConstraints ได้ ข้อจำกัด
ในการวัดผล
จะอยู่ในขอบเขตของ Lambda เนื้อหา คุณสามารถใช้ข้อจำกัดในการวัดผลเหล่านี้เพื่อสร้างเลย์เอาต์ต่างๆ สำหรับการกำหนดค่าหน้าจอที่แตกต่างกันได้
@Composable fun WithConstraintsComposable() { BoxWithConstraints { Text("My minHeight is $minHeight while my maxWidth is $maxWidth") } }
เลย์เอาต์ตามช่อง
Compose มี Composable มากมายที่อิงตาม Material
Design พร้อมandroidx.compose.material:material Dependency (รวมอยู่ด้วยเมื่อสร้างโปรเจ็กต์ Compose ใน Android Studio) เพื่อให้การสร้าง UI เป็นเรื่องง่าย โดยมีองค์ประกอบต่างๆ เช่น
Drawer
FloatingActionButton
และ TopAppBar
คอมโพเนนต์ Material ใช้ API ช่อง อย่างมาก ซึ่งเป็นรูปแบบที่ Compose นำมาใช้
เพื่อเพิ่มเลเยอร์การปรับแต่งไว้เหนือ Composable แนวทางนี้ช่วยให้คอมโพเนนต์มีความยืดหยุ่นมากขึ้น เนื่องจากยอมรับองค์ประกอบย่อยที่กำหนดค่าตัวเองได้ แทนที่จะต้องแสดงพารามิเตอร์การกำหนดค่าทั้งหมดขององค์ประกอบย่อย
โดยช่องจะเว้นที่ว่างใน UI ไว้ให้นักพัฒนาแอปใส่เนื้อหาตามต้องการ ตัวอย่างเช่น ช่องที่คุณปรับแต่งได้ในTopAppBar มีดังนี้
โดยปกติแล้ว Composable จะใช้ content Composable Lambda ( content: @Composable
() -> Unit) API ของช่องจะแสดงพารามิเตอร์ content หลายรายการสำหรับการใช้งานที่เฉพาะเจาะจง
เช่น TopAppBar ช่วยให้คุณระบุเนื้อหาสำหรับ title, navigationIcon และ actions ได้
เช่น
Scaffold
ช่วยให้คุณใช้ UI ที่มีโครงสร้างเลย์เอาต์ Material Design พื้นฐานได้
Scaffoldมีช่องสำหรับคอมโพเนนต์ Material ระดับบนสุดที่พบบ่อยที่สุด
เช่น TopAppBar
BottomAppBar
FloatingActionButton
และ Drawer การใช้
Scaffold ช่วยให้มั่นใจได้ง่ายๆ ว่าคอมโพเนนต์เหล่านี้อยู่ในตำแหน่งที่เหมาะสมและ
ทำงานร่วมกันได้อย่างถูกต้อง
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ตัวแก้ไขการเขียน
- Kotlin สำหรับ Jetpack Compose
- คอมโพเนนต์และเลย์เอาต์ของ Material