ตัวแก้ไขช่วยให้คุณตกแต่งหรือเพิ่มฟังก์ชันให้กับ 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
และ
Box
ที่ 2 กว้าง 70.dp
@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 ในกรณีของตัวแก้ไขที่ไม่มีขอบเขต คุณสามารถดึงข้อมูลตัวแก้ไขเหล่านั้นออกมา นอก 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 }