ตัวปรับแต่งช่วยให้คุณตกแต่งหรือเพิ่ม Composable ได้ ตัวแก้ไขช่วยให้คุณทำสิ่งต่อไปนี้ได้
- เปลี่ยนขนาด เลย์เอาต์ ลักษณะการทำงาน และลักษณะที่ปรากฏของ Composable
- เพิ่มข้อมูล เช่น ป้ายกำกับการช่วยเหลือพิเศษ
- ประมวลผลอินพุตของผู้ใช้
- เพิ่มการโต้ตอบระดับสูง เช่น การทําให้องค์ประกอบคลิกได้ เลื่อนได้ ลากได้ หรือซูมได้
ตัวแก้ไขเป็นออบเจ็กต์ Kotlin มาตรฐาน สร้างตัวแก้ไขโดยเรียกใช้ฟังก์ชันคลาสใดคลาสหนึ่งต่อไปนี้
Modifier
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
คุณสามารถเชื่อมโยงฟังก์ชันเหล่านี้เข้าด้วยกันเพื่อสร้างฟังก์ชันใหม่ได้โดยทำดังนี้
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
ในโค้ดด้านบน ให้สังเกตฟังก์ชันตัวแก้ไขต่างๆ ที่ใช้ร่วมกัน
paddingจะเว้นที่ว่างรอบองค์ประกอบfillMaxWidthทำให้ Composable เติมความกว้างสูงสุดที่ได้รับจาก องค์ประกอบระดับบน
แนวทางปฏิบัติแนะนำคือให้ Composable ทั้งหมดยอมรับพารามิเตอร์ modifier
และส่งตัวแก้ไขนั้นไปยังองค์ประกอบย่อยแรกที่ปล่อย UI
การทำเช่นนี้จะทำให้โค้ดของคุณนำกลับมาใช้ซ้ำได้มากขึ้น และทำให้ลักษณะการทำงานของโค้ดคาดการณ์ได้ง่ายขึ้นและใช้งานง่ายขึ้น ดูข้อมูลเพิ่มเติมได้ที่หลักเกณฑ์ของ Compose API, Elements accept and respect a
Modifier parameter
ลำดับของตัวแก้ไขมีความสำคัญ
ลำดับของฟังก์ชันตัวแก้ไขมีความสำคัญ เนื่องจากแต่ละฟังก์ชันจะทำการเปลี่ยนแปลงกับModifierที่ฟังก์ชันก่อนหน้าแสดงผล ลำดับจึงส่งผลต่อผลลัพธ์สุดท้าย มาดูตัวอย่างกัน
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
ในโค้ดด้านบน พื้นที่ทั้งหมดจะคลิกได้ รวมถึงระยะห่างภายในโดยรอบ เนื่องจากมีการใช้ตัวแก้ไข padding หลังจากตัวแก้ไข clickable
หากลำดับตัวแก้ไขกลับกัน ช่องว่างที่เพิ่มโดย padding จะไม่ตอบสนองต่ออินพุตของผู้ใช้
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
ตัวปรับแต่งในตัว
Jetpack Compose มีรายการตัวแก้ไขในตัวที่จะช่วยคุณตกแต่งหรือ เพิ่มฟังก์ชันการทำงานให้กับ Composable ตัวปรับแต่งทั่วไปที่คุณจะใช้เพื่อปรับเลย์เอาต์มีดังนี้
padding และ size
โดยค่าเริ่มต้น เลย์เอาต์ที่ระบุใน Compose จะตัดข้อความขององค์ประกอบย่อย แต่คุณสามารถกำหนดขนาดได้โดยใช้ตัวแก้ไข size
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
โปรดทราบว่าระบบอาจไม่ใช้ขนาดที่คุณระบุหากไม่เป็นไปตามข้อจำกัดจากองค์ประกอบหลักของเลย์เอาต์
หากต้องการให้ขนาดของ Composable
คงที่โดยไม่คำนึงถึงข้อจำกัดที่เข้ามา ให้ใช้ตัวแก้ไข requiredSize
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
ในตัวอย่างนี้ แม้ว่าองค์ประกอบหลัก height จะตั้งค่าเป็น 100.dp แต่ความสูงของ
Image จะเป็น 150.dp เนื่องจากตัวแก้ไข requiredSize มี
ลำดับความสำคัญสูงกว่า
หากต้องการให้เลย์เอาต์ย่อยเติมความสูงทั้งหมดที่เลย์เอาต์หลักอนุญาต ให้เพิ่มตัวแก้ไข fillMaxHeight (Compose ยังมี fillMaxSize และ fillMaxWidth ด้วย)
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
หากต้องการเพิ่มระยะห่างจากขอบรอบๆ องค์ประกอบ ให้ตั้งค่าตัวแก้ไข padding
หากต้องการเพิ่มระยะห่างเหนือบรรทัดฐานของข้อความเพื่อให้ได้
ระยะห่างที่เฉพาะเจาะจงจากด้านบนของเลย์เอาต์ไปยังบรรทัดฐาน ให้ใช้ตัวแก้ไข paddingFromBaseline ดังนี้
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
ออฟเซ็ต
หากต้องการวางเลย์เอาต์เทียบกับตำแหน่งเดิม ให้เพิ่มตัวแก้ไข offset แล้วตั้งค่าออฟเซ็ตในแกน x และ y
โดยออฟเซ็ตอาจเป็นค่าบวกหรือค่าที่ไม่ใช่ค่าบวกก็ได้ ความแตกต่างระหว่าง
padding กับ offset คือการเพิ่ม offset ลงใน Composable จะไม่
เปลี่ยนการวัดผล
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
ระบบจะใช้ตัวแก้ไข offset ในแนวนอนตามทิศทางเลย์เอาต์
ในบริบทจากซ้ายไปขวา ค่าบวก offset จะเลื่อนองค์ประกอบไปทางขวา ส่วนในบริบทจากขวาไปซ้าย ค่าบวกจะเลื่อนองค์ประกอบไปทางซ้าย
หากต้องการตั้งค่าออฟเซ็ตโดยไม่คำนึงถึงทิศทางการจัดวาง ให้ดูตัวแก้ไข
absoluteOffset
ซึ่งค่าออฟเซ็ตที่เป็นบวกจะเลื่อนองค์ประกอบไปทางขวาเสมอ
ตัวปรับแต่ง offset มีการโอเวอร์โหลด 2 รายการ ได้แก่ offset ที่ใช้ค่าออฟเซ็ตเป็นพารามิเตอร์ และ offset ที่ใช้แลมบ์ดา
ดูข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับเวลาที่ควรใช้แต่ละรายการและวิธีเพิ่มประสิทธิภาพ
เพื่อประสิทธิภาพได้ในส่วนประสิทธิภาพของ Compose - เลื่อนการอ่านให้นานที่สุด
ขอบเขตความปลอดภัยใน Compose
ใน Compose มีตัวแก้ไขที่ใช้ได้เฉพาะเมื่อใช้กับองค์ประกอบย่อย ของ Composable บางรายการ Compose บังคับใช้สิ่งนี้ผ่านขอบเขตที่กำหนดเอง
เช่น หากต้องการให้องค์ประกอบย่อยมีขนาดเท่ากับองค์ประกอบหลักBoxโดยไม่Boxส่งผลต่อขนาด ให้ใช้ตัวแก้ไข
matchParentSize
matchParentSize จะมีเฉพาะใน
BoxScope
ดังนั้นจึงใช้ได้เฉพาะกับบุตรหลานภายในบัญชีผู้ปกครอง Box
ความปลอดภัยของขอบเขตช่วยป้องกันไม่ให้คุณเพิ่มตัวแก้ไขที่ใช้ไม่ได้ใน Composable และขอบเขตอื่นๆ รวมถึงช่วยประหยัดเวลาจากการลองผิดลองถูก
ตัวแก้ไขที่กำหนดขอบเขตจะแจ้งให้ผู้ปกครองทราบเกี่ยวกับข้อมูลบางอย่างที่ผู้ปกครอง ควรรู้เกี่ยวกับบุตรหลาน ซึ่งมักเรียกกันว่าตัวแก้ไขข้อมูลระดับบนสุด การทำงานภายในของตัวแก้ไขเหล่านี้แตกต่างจากตัวแก้ไขอเนกประสงค์ แต่ในมุมมองการใช้งาน ความแตกต่างเหล่านี้ไม่สำคัญ
matchParentSizeในBox
ดังที่กล่าวไว้ข้างต้น หากต้องการให้เลย์เอาต์ย่อยมีขนาดเท่ากับเลย์เอาต์หลัก
Box โดยไม่ส่งผลต่อBox ขนาด ให้ใช้ตัวแก้ไข matchParentSize
โปรดทราบว่า matchParentSize จะใช้ได้ภายในขอบเขต Box เท่านั้น ซึ่งหมายความว่า
จะมีผลกับองค์ประกอบที่ใช้ได้ของ Box ที่เป็นองค์ประกอบย่อยโดยตรงเท่านั้น
ในตัวอย่างด้านล่าง Spacer จะใช้ขนาดจากองค์ประกอบหลัก Box
ซึ่งจะใช้ขนาดจากองค์ประกอบย่อยที่ใหญ่ที่สุด
ArtistCard ในกรณีนี้
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
หากใช้ fillMaxSize แทน matchParentSize Spacer จะใช้
พื้นที่ว่างทั้งหมดที่อนุญาตให้ผู้ปกครองใช้ ซึ่งจะทำให้ผู้ปกครอง
ขยายและใช้พื้นที่ว่างทั้งหมด
weight ใน Row และ Column
ดังที่ได้เห็นในส่วนก่อนหน้าเกี่ยวกับระยะขอบและขนาด โดยค่าเริ่มต้น ระบบจะกำหนดขนาดที่ประกอบได้ตามเนื้อหาที่ห่อหุ้ม คุณสามารถตั้งค่าขนาดของ Composable ให้ยืดหยุ่นภายใน
องค์ประกอบระดับบนได้โดยใช้ weight Modifier ที่ใช้ได้เฉพาะใน RowScope และ
ColumnScope
มาดู Row ที่มี Composable 2 รายการ Box กัน
กล่องแรกมี weight เป็น 2 เท่าของกล่องที่ 2 จึงมี
ความกว้างเป็น 2 เท่า เนื่องจาก Row กว้าง 210.dp ดังนั้น Box แรกจึงกว้าง 140.dp และ
70.dp ที่ 2 มีขนาดดังนี้
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
การแยกและนำตัวแก้ไขกลับมาใช้ใหม่
คุณสามารถเชื่อมต่อตัวแก้ไขหลายรายการเข้าด้วยกันเพื่อตกแต่งหรือ
เพิ่มฟังก์ชันให้กับ Composable เชนนี้สร้างขึ้นผ่านอินเทอร์เฟซ Modifier
ซึ่งแสดงรายการ Modifier.Elements เดียวที่เรียงลำดับและเปลี่ยนแปลงไม่ได้
แต่ละ Modifier.Element แสดงถึงลักษณะการทำงานแต่ละอย่าง เช่น เลย์เอาต์ การวาด
และลักษณะการทำงานของกราฟิก ลักษณะการทำงานที่เกี่ยวข้องกับท่าทางสัมผัสทั้งหมด ลักษณะการทำงานของโฟกัสและความหมาย รวมถึง
เหตุการณ์อินพุตของอุปกรณ์ ลำดับขององค์ประกอบตัวแก้ไขมีความสำคัญ โดยองค์ประกอบตัวแก้ไขที่เพิ่มก่อนจะได้รับการใช้ก่อน
บางครั้งการนำอินสแตนซ์ของเชนตัวแก้ไขเดียวกันกลับมาใช้ซ้ำใน Composable หลายรายการอาจเป็นประโยชน์ โดยการแยกอินสแตนซ์เหล่านั้นเป็นตัวแปรและย้ายไปยังขอบเขตที่สูงขึ้น ซึ่งจะช่วยปรับปรุงความสามารถในการอ่านโค้ดหรือช่วยปรับปรุงประสิทธิภาพของแอปได้ด้วยเหตุผลต่อไปนี้
- ระบบจะไม่ทำซ้ำการจัดสรรตัวแก้ไขใหม่เมื่อมีการจัดองค์ประกอบใหม่ สำหรับ Composable ที่ใช้ตัวแก้ไข
- เชนตัวแก้ไขอาจยาวและซับซ้อนมาก ดังนั้นการนำอินสแตนซ์ของเชนเดียวกันมาใช้ซ้ำจะช่วยลดภาระงานที่รันไทม์ของ Compose ต้องทำเมื่อเปรียบเทียบเชน
- การแยกนี้ช่วยส่งเสริมความสะอาด ความสอดคล้อง และความสามารถในการบำรุงรักษาโค้ด ในโค้ดเบส
แนวทางปฏิบัติแนะนำสำหรับการใช้ตัวแก้ไขซ้ำ
สร้างModifierเชนของคุณเองและดึงข้อมูลเพื่อนำไปใช้ซ้ำในคอมโพเนนต์ที่ประกอบได้หลายรายการ
คุณจะบันทึกเฉพาะตัวแก้ไขก็ได้ เนื่องจากตัวแก้ไขเป็นออบเจ็กต์ที่คล้ายข้อมูล
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
การแยกและนำตัวแก้ไขมาใช้ซ้ำเมื่อสังเกตสถานะที่เปลี่ยนแปลงบ่อย
เมื่อสังเกตสถานะที่เปลี่ยนแปลงบ่อยภายใน Composable เช่น สถานะของภาพเคลื่อนไหวหรือ scrollState อาจมีการ Recomposition จำนวนมาก
ในกรณีนี้ ระบบจะจัดสรรตัวปรับแต่งในการจัดองค์ประกอบใหม่ทุกครั้ง
และอาจเป็นทุกเฟรม
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
แต่คุณสามารถสร้าง แยก และนำอินสแตนซ์ตัวแก้ไขเดียวกันมาใช้ซ้ำ และส่งไปยัง Composable ได้ดังนี้
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
การแยกและนำตัวแก้ไขที่ไม่มีขอบเขตกลับมาใช้ใหม่
โดยตัวแก้ไขอาจไม่มีขอบเขตหรือมีขอบเขตเฉพาะ คอมโพสได้ ในกรณีของตัวแก้ไขที่ไม่มีขอบเขต คุณสามารถดึงข้อมูลตัวแก้ไขเหล่านั้นออกมา นอก Composable ใดๆ ได้อย่างง่ายดายในรูปแบบตัวแปรธรรมดา
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
ซึ่งจะมีประโยชน์อย่างยิ่งเมื่อใช้ร่วมกับเลย์เอาต์แบบเลซี ในกรณีส่วนใหญ่ คุณอาจต้องการให้สินค้าทั้งหมดที่มีจำนวนมากและอาจมีความสำคัญมีตัวแก้ไขเหมือนกันทุกประการ ดังนี้
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
การแยกและการนำตัวแก้ไขที่กำหนดขอบเขตมาใช้ซ้ำ
เมื่อต้องจัดการกับตัวแก้ไขที่มีขอบเขตเป็น Composable บางรายการ คุณสามารถ ดึงข้อมูลไปยังระดับสูงสุดเท่าที่จะเป็นไปได้และนำกลับมาใช้ใหม่ได้ตามความเหมาะสม
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
คุณควรส่งเฉพาะตัวแก้ไขที่ขอบเขตที่แยกออกมาไปยังองค์ประกอบย่อยโดยตรงที่มีขอบเขตเดียวกันเท่านั้น ดูข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่เรื่องนี้มีความสำคัญได้ที่ส่วนความปลอดภัยของขอบเขตใน Compose
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
การเชื่อมต่อตัวแก้ไขที่แยกออกมาเพิ่มเติม
คุณสามารถเชื่อมโยงหรือต่อท้ายเชนตัวแก้ไขที่แยกออกมาได้โดยเรียกใช้ฟังก์ชัน
.then()
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
โปรดทราบว่าลำดับของตัวแก้ไขมีความสำคัญ
ดูข้อมูลเพิ่มเติม
เรามีรายการตัวแก้ไขทั้งหมดพร้อมพารามิเตอร์และขอบเขต
หากต้องการฝึกวิธีใช้ตัวปรับแต่งเพิ่มเติม คุณสามารถดู Codelab เลย์เอาต์พื้นฐานใน Compose หรือดู ที่เก็บ Now in Android
ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวแก้ไขที่กำหนดเองและวิธีสร้างได้ที่ เอกสารประกอบเกี่ยวกับเลย์เอาต์ที่กำหนดเอง - การใช้ตัวแก้ไขเลย์เอาต์
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ข้อมูลเบื้องต้นเกี่ยวกับเลย์เอาต์การเขียน
- การดำเนินการของเอดิเตอร์ {:#editor-actions}
- เลย์เอาต์ที่กำหนดเอง {:#custom-layouts }