Jetpack Compose ช่วยให้การออกแบบและสร้าง UI ของแอปง่ายขึ้นมาก Compose เปลี่ยนสถานะเป็นองค์ประกอบ UI ผ่าน
- การเรียบเรียงองค์ประกอบ
- เลย์เอาต์ขององค์ประกอบ
- การวาดองค์ประกอบ
เอกสารนี้มุ่งเน้นที่เลย์เอาต์ขององค์ประกอบ โดยจะอธิบายบล็อกการสร้างบางอย่างที่ Compose มีให้เพื่อช่วยคุณจัดวางองค์ประกอบ UI
เป้าหมายของเลย์เอาต์ในฟีเจอร์เขียน
การใช้งานระบบเลย์เอาต์ของ 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ขอให้โหนดลูกที่ 2 ซึ่งก็คือColumnทำการวัด - โหนด
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ทำให้ Composable ตอบสนองต่ออินพุตของผู้ใช้และแสดงการกระเพื่อม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 (รวมอยู่ด้วยเมื่อสร้างโปรเจ็กต์ 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