ตัวแก้ไขช่วยให้คุณตกแต่งหรือเพิ่มองค์ประกอบให้กับคอมโพสิเบิลได้ ตัวแก้ไขช่วยให้คุณทําสิ่งต่อไปนี้ได้
- เปลี่ยนขนาด เลย์เอาต์ ลักษณะการทำงาน และลักษณะที่ปรากฏของคอมโพสิเบิล
- เพิ่มข้อมูล เช่น ป้ายกำกับการช่วยเหลือพิเศษ
- ประมวลผลข้อมูลที่ได้จากผู้ใช้
- เพิ่มการโต้ตอบระดับสูง เช่น ทําให้องค์ประกอบคลิกได้ เลื่อนได้ ลากได้ หรือซูมได้
ตัวแก้ไขคือออบเจ็กต์ 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
ทําให้คอมโพสิเบิลเติมความกว้างสูงสุดที่ได้รับจากส่วนกลาง
แนวทางปฏิบัติแนะนำคือให้คอมโพสิเบิลทั้งหมดยอมรับพารามิเตอร์ 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 มีรายการตัวแก้ไขในตัวเพื่อช่วยตกแต่งหรือเพิ่มประสิทธิภาพคอมโพสิเบิล ต่อไปนี้คือตัวแก้ไขทั่วไปที่คุณจะใช้เพื่อปรับเลย์เอาต์
padding
และ size
โดยค่าเริ่มต้น เลย์เอาต์ที่ระบุใน "เขียน" จะตัดขึ้นบรรทัดใหม่สำหรับองค์ประกอบย่อย แต่คุณสามารถกำหนดขนาดได้โดยใช้ตัวแก้ไข size
ดังนี้
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
โปรดทราบว่าระบบอาจไม่ใช้ขนาดที่คุณระบุหากไม่เป็นไปตามข้อจำกัดที่มาจากรายการหลักของเลย์เอาต์ หากต้องการให้คอมโพสิเบิลมีขนาดคงที่ ไม่ว่าจะมีข้อจำกัดใดเข้ามาก็ตาม ให้ใช้ตัวแก้ไข 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
(คอมโพซยังมี 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 fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
ตัวแก้ไข offset
จะใช้ในแนวนอนตามทิศทางของเลย์เอาต์
ในบริบทซ้ายไปขวา offset
ที่เป็นบวกจะเลื่อนองค์ประกอบไปทางขวา ส่วนในบริบทขวาไปซ้าย offset
ที่เป็นบวกจะเลื่อนองค์ประกอบไปทางซ้าย
หากต้องการตั้งค่าออฟเซ็ตโดยไม่คำนึงถึงทิศทางของเลย์เอาต์ ให้ดูที่ตัวแก้ไข absoluteOffset
ซึ่งค่าออฟเซ็ตที่เป็นบวกจะเลื่อนองค์ประกอบไปทางขวาเสมอ
ตัวแก้ไข offset
มีการโอเวอร์โหลด 2 รายการ ได้แก่ offset
ที่ใช้ออฟเซตเป็นพารามิเตอร์ และ offset
ที่ใช้ Lambda
ดูข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับกรณีที่ควรใช้แต่ละรายการและวิธีเพิ่มประสิทธิภาพได้ที่ส่วนประสิทธิภาพการเขียน - เลื่อนการอ่านไว้นานที่สุด
ความปลอดภัยของขอบเขตใน Compose
ใน Compose มีตัวปรับเปลี่ยนที่ใช้ได้เฉพาะกับองค์ประกอบย่อยของคอมโพสิเบิลบางรายการเท่านั้น Compose บังคับใช้สิ่งนี้ด้วยขอบเขตที่กำหนดเอง
เช่น หากต้องการทําให้องค์ประกอบย่อยมีขนาดใหญ่เท่ากับองค์ประกอบหลัก Box
โดยไม่ส่งผลต่อขนาด Box
ให้ใช้ตัวแก้ไข matchParentSize
matchParentSize
มีให้บริการใน BoxScope
เท่านั้น
ดังนั้นจึงใช้ได้กับรายการย่อยภายในรายการหลัก Box
เท่านั้น
ความปลอดภัยของขอบเขตจะป้องกันไม่ให้คุณเพิ่มตัวแก้ไขที่ไม่ทำงานในคอมโพสิเบิลและขอบเขตอื่นๆ และช่วยประหยัดเวลาในการลองผิดลองถูก
ตัวแก้ไขที่มีขอบเขตจะแจ้งให้ผู้ปกครองทราบข้อมูลบางอย่างที่ผู้ปกครองควรทราบเกี่ยวกับบุตรหลาน ซึ่งเรียกกันโดยทั่วไปว่าตัวแก้ไขข้อมูลหลัก โครงสร้างภายในของคำเหล่านี้แตกต่างจากตัวหลีกทั่วไป แต่ความแตกต่างเหล่านี้ไม่สำคัญต่อการใช้งาน
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
ที่มีคอมโพสิเบิล Box
2 รายการ
กล่องแรกมี 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) ) { /*...*/ } } }
การคลายไฟล์และนำตัวแก้ไขมาใช้ซ้ำ
คุณสามารถใช้ตัวแก้ไขหลายรายการต่อกันเพื่อตกแต่งหรือเพิ่มประสิทธิภาพคอมโพสิเบิลได้ เชนนี้สร้างขึ้นผ่านอินเทอร์เฟซ Modifier
ซึ่งแสดงรายการ Modifier.Elements
รายการเดียวที่จัดเรียงและแก้ไขไม่ได้
Modifier.Element
แต่ละรายการแสดงถึงลักษณะการทํางานแต่ละอย่าง เช่น ลักษณะการทํางานของเลย์เอาต์ การวาด และกราฟิก ลักษณะการทํางานที่เกี่ยวข้องกับท่าทางสัมผัส โฟกัส และความหมายทั้งหมด รวมถึงเหตุการณ์อินพุตของอุปกรณ์ ลําดับขององค์ประกอบเหล่านี้มีความสำคัญ โดยระบบจะใช้องค์ประกอบตัวแก้ไขที่เพิ่มไว้ก่อน
บางครั้งการนำอินสแตนซ์ของเชนตัวแก้ไขเดียวกันมาใช้ซ้ำในคอมโพสิเบิลหลายรายการอาจมีประโยชน์ โดยดึงข้อมูลอินสแตนซ์เหล่านั้นไปยังตัวแปรและยกระดับไปยังขอบเขตที่สูงขึ้น ซึ่งช่วยปรับปรุงความอ่านง่ายของโค้ดหรือช่วยปรับปรุงประสิทธิภาพของแอปได้ ดังนี้
- ระบบจะไม่จัดสรรตัวแก้ไขใหม่อีกเมื่อมีการจัดองค์ประกอบใหม่สำหรับคอมโพสิเบิลที่ใช้ตัวแก้ไข
- เชนตัวแก้ไขอาจยาวและซับซ้อนมาก ดังนั้นการนำอินสแตนซ์เดิมของเชนมาใช้ซ้ำจะช่วยลดความซับซ้อนของภาระงานที่รันไทม์ Compose ต้องทำเมื่อเปรียบเทียบเชน
- การสกัดนี้ช่วยเพิ่มความสะอาด ความสอดคล้อง และการบำรุงรักษาโค้ดได้ทั่วทั้งฐานโค้ด
แนวทางปฏิบัติแนะนำในการใช้ตัวแก้ไขซ้ำ
สร้างเชน Modifier
ของคุณเองและดึงข้อมูลเชนดังกล่าวเพื่อนำไปใช้ซ้ำในคอมโพเนนต์แบบคอมโพสิเบิลหลายรายการ คุณบันทึกตัวแก้ไขเพียงอย่างเดียวได้ เนื่องจากตัวแก้ไขเป็นออบเจ็กต์ที่คล้ายกับข้อมูล
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
ดึงข้อมูลและนําตัวแก้ไขมาใช้ซ้ำเมื่อสังเกตสถานะที่เปลี่ยนแปลงบ่อย
เมื่อสังเกตสถานะที่เปลี่ยนแปลงบ่อยภายในคอมโพสิเบิล เช่น สถานะภาพเคลื่อนไหวหรือ 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 ) }
แต่คุณสามารถสร้าง ดึงข้อมูล และนําอินสแตนซ์เดิมของมอดิวเลเตอร์มาใช้ซ้ำได้ และส่งไปยังคอมโพสิเบิลดังนี้
// 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 ) }
การสกัดและนําตัวแก้ไขที่ไม่มีขอบเขตมาใช้ซ้ำ
คุณยกเลิกการกำหนดขอบเขตหรือกำหนดขอบเขตให้กับคอมโพสิเบิลที่เฉพาะเจาะจงได้ ในกรณีของมิเตอร์ที่มีขอบเขตไม่จำกัด คุณสามารถดึงข้อมูลมิเตอร์เหล่านั้นออกจากคอมโพสิเบิลต่างๆ ได้อย่างง่ายดายโดยใช้ตัวแปรธรรมดา ดังนี้
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
ซึ่งจะเป็นประโยชน์อย่างยิ่งเมื่อใช้ร่วมกับเลย์เอาต์แบบ Lazy ในกรณีส่วนใหญ่ คุณควรให้รายการทั้งหมดที่มีจำนวนมาก (ซึ่งอาจมาก) ของคุณมีตัวแก้ไขเดียวกันทุกประการ ดังนี้
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, ) } } }
การสกัดและนําตัวแก้ไขที่มีขอบเขตมาใช้ซ้ำ
เมื่อจัดการกับตัวแก้ไขที่มีขอบเขตระดับคอมโพสิเบิลบางรายการ คุณสามารถดึงข้อมูลตัวแก้ไขดังกล่าวไปยังระดับสูงสุดที่เป็นไปได้และนําไปใช้ซ้ำตามความเหมาะสมได้ ดังนี้
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 หรือดูตอนนี้ในที่เก็บข้อมูล Android ได้ด้วย
ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวแก้ไขที่กำหนดเองและวิธีสร้างได้ที่เอกสารประกอบเกี่ยวกับเลย์เอาต์ที่กำหนดเอง - การใช้ตัวแก้ไขเลย์เอาต์
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ข้อมูลเบื้องต้นเกี่ยวกับการจัดวาง
- การดำเนินการของเครื่องมือแก้ไข {:#editor-actions}
- เลย์เอาต์ที่กำหนดเอง {:#custom-layouts }