ตัวปรับแต่งช่วยให้คุณตกแต่งหรือเพิ่ม 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, องค์ประกอบต่างๆ ยอมรับและดำเนินการตาม
พารามิเตอร์ตัวปรับแต่ง
ลำดับของคีย์ตัวปรับแต่งมีความสำคัญ
ลําดับของฟังก์ชันตัวปรับแต่งมีนัยสำคัญ เนื่องจากแต่ละฟังก์ชันจะทำให้
เปลี่ยนเป็น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
ที่ใช้ lambda
หากต้องการข้อมูลเชิงลึกเพิ่มเติมว่าควรใช้โซลูชันเหล่านี้เมื่อใด และวิธีเพิ่มประสิทธิภาพ
สำหรับประสิทธิภาพ โปรดอ่าน
ประสิทธิภาพการเขียน - เลื่อนการอ่านให้นานที่สุด
กำหนดขอบเขตความปลอดภัยของการเขียน
ใน Compose มีตัวแก้ไขที่ใช้ได้เฉพาะเมื่อมีผลกับรายการย่อยเท่านั้น Composable บางรายการ Compose จะบังคับใช้ขอบเขตนี้โดยใช้ขอบเขตที่กำหนดเอง
เช่น หากต้องการกำหนดให้บุตรหลานใหญ่เท่ากับบัญชีหลักBox
โดยไม่มี
ส่งผลต่อขนาด Box
ให้ใช้
matchParentSize
แป้นกดร่วม matchParentSize
พร้อมให้ใช้งานเฉพาะใน
BoxScope
ดังนั้นจึงใช้ได้กับรายการย่อยภายใน Box
ระดับบนสุดเท่านั้น
ความปลอดภัยของขอบเขตช่วยให้คุณเพิ่มตัวแก้ไขที่จะใช้งานไม่ได้ใน Composable และขอบเขต ซึ่งช่วยประหยัดเวลาจากการลองผิดลองถูก
ตัวแก้ไขที่กำหนดขอบเขตจะแจ้งให้ผู้ปกครองทราบเกี่ยวกับข้อมูลบางอย่างที่ผู้ปกครอง ควรรู้จักเด็ก หรือเรียกกันโดยทั่วไปว่า ตัวแก้ไขข้อมูลหลัก ความเป็นภายในขององค์กรแตกต่างจากจุดประสงค์ทั่วไป ตัวแก้ไข แต่จากมุมมองการใช้งาน ความแตกต่างเหล่านี้ไม่ใช่สิ่งสำคัญ
matchParentSize
ในBox
ตามที่กล่าวไว้ข้างต้น หากคุณต้องการให้เลย์เอาต์ย่อยมีขนาดเท่ากับหน่วยโฆษณาหลัก
Box
โดยไม่ส่งผลต่อขนาด Box
ให้ใช้ตัวแก้ไข matchParentSize
โปรดทราบว่า matchParentSize
พร้อมใช้งานภายในขอบเขต Box
เท่านั้น ซึ่งหมายความว่า
ก็จะใช้ได้เฉพาะกับองค์ประกอบย่อยโดยตรงของ Composable Box
ในตัวอย่างด้านล่าง ย่อย Spacer
นำขนาดมาจาก Box
ระดับบน
ซึ่งนำขนาดมาจากเด็กๆ ที่โตที่สุด
ในกรณีนี้คือ ArtistCard
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
หากใช้ fillMaxSize
แทน matchParentSize
ระบบจะใช้ Spacer
พื้นที่ว่างทั้งหมดที่ผู้ปกครองอนุญาต ซึ่งจะส่งผลให้ผู้ปกครอง
ขยายและเติมพื้นที่ว่างทั้งหมดที่มีอยู่
weight
ในRow
และColumn
อย่างที่คุณได้เห็นในส่วนก่อนหน้านี้เกี่ยวกับระยะห่างจากขอบและ
size [ขนาด] โดยค่าเริ่มต้น ขนาด Composable จะกำหนดโดยแอตทริบิวต์
เนื้อหาที่ห่อหุ้มอยู่ คุณสามารถตั้งค่าขนาด Composable ให้ยืดหยุ่นภายใน
ผู้ปกครองที่ใช้ตัวปรับแต่ง weight
ที่มีเฉพาะใน RowScope
และ
ColumnScope
ลองพิจารณา Row
ที่มี Composable Box
2 รายการ
ช่องแรกมีสองเท่าของ weight
ของช่องที่สอง ดังนั้นช่องนี้จึงได้รับสองเท่าของ
ความกว้าง เนื่องจาก Row
กว้าง 210.dp
ค่า Box
แรกจึงกว้าง 140.dp
และ
รายการที่ 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 หลายรายการโดยการแยกเป็นตัวแปรและคัดลอกลงใน ในระดับที่สูงขึ้น ทำให้โค้ดอ่านง่ายขึ้นหรือช่วยปรับปรุง ประสิทธิภาพเนื่องจากเหตุผล 2-3 ประการ
- ระบบจะไม่ทำซ้ำการจัดสรรตัวแก้ไขใหม่เมื่อจัดองค์ประกอบใหม่ Composable ที่ใช้คอมโพเนนต์
- ห่วงโซ่ตัวปรับแต่งอาจยาวและซับซ้อนมาก ดังนั้นการนำโค้ด อินสแตนซ์เดียวกันของเชนจะช่วยลดภาระงานที่รันไทม์ของ Compose ต้องทำได้ เมื่อเปรียบเทียบ
- การแยกออกนี้จะสนับสนุนความสะอาดของโค้ด ความสอดคล้อง และการบำรุงรักษา ในฐานของโค้ด
แนวทางปฏิบัติแนะนำในการใช้ตัวแก้ไขซ้ำ
สร้างเชน Modifier
ของคุณเองและแตกข้อมูลเพื่อนำกลับมาใช้ซ้ำในหลายเชน
Composable การบันทึกตัวปรับแต่งอย่างเดียวก็ไม่เป็นไร เนื่องจาก
เป็นวัตถุที่มีลักษณะคล้ายข้อมูล
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
การแยกและนำตัวปรับไปใช้ซ้ำเมื่อสังเกตสถานะที่เปลี่ยนแปลงบ่อย
เมื่อสังเกตสถานะที่เปลี่ยนแปลงบ่อยภายใน Composable เช่น ภาพเคลื่อนไหว
หรือ scrollState
ก็อาจทำให้มีการจัดองค์ประกอบใหม่
เสร็จสิ้น ในกรณีนี้ ตัวแก้ไขจะได้รับการจัดสรรในทุกๆ การจัดองค์ประกอบใหม่
และเป็นไปได้สำหรับทุกเฟรม
@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 ) }
ซึ่งจะเป็นประโยชน์อย่างยิ่งเมื่อใช้ร่วมกับเลย์เอาต์แบบ Lazy Loading ส่วนใหญ่ คุณต้องเตรียมรายการทั้งหมดที่มีนัยสำคัญ คีย์ตัวปรับแต่งที่เหมือนกันทุกประการ ได้แก่
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 // ... ) // ... }
คุณควรส่งเฉพาะตัวแก้ไขที่กำหนดขอบเขตที่ดึงข้อมูลมาไปยัง ในขอบเขตเดียวกัน และกำหนดเป้าหมายไปที่เด็กโดยตรง โปรดดูส่วนความปลอดภัยด้านขอบเขตใน เขียนเพื่อใช้อ้างอิงเพิ่มเติมว่าสำคัญอย่างไร
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)
แต่อย่าลืมว่าลำดับของตัวแก้ไขมีความสำคัญ
ดูข้อมูลเพิ่มเติม
เรามีรายการตัวปรับแต่งทั้งหมด พร้อมด้วย พารามิเตอร์และขอบเขต
หากต้องการฝึกฝนเพิ่มเติมเกี่ยวกับวิธีใช้ตัวแก้ไข โปรดดู เลย์เอาต์พื้นฐานใน Compose Codelab หรือดูที่ อยู่ในที่เก็บ Android แล้ว
ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวแก้ไขที่กำหนดเองและวิธีสร้างตัวแก้ไขได้ที่ เอกสารประกอบเกี่ยวกับเลย์เอาต์ที่กำหนดเอง - การใช้ตัวแก้ไขเลย์เอาต์
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ข้อมูลเบื้องต้นเกี่ยวกับเลย์เอาต์สำหรับการเขียน
- การดำเนินการของผู้แก้ไข {:#editor-actions}
- เลย์เอาต์ที่กำหนดเอง {:#custom-layouts }