ตัวปรับแต่งช่วยให้คุณตกแต่งหรือเพิ่ม 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
ลำดับของตัวแก้ไขมีความสำคัญ
ลำดับของฟังก์ชันตัวแก้ไขเป็นสิ่งสำคัญ เนื่องจากแต่ละฟังก์ชันจะทำการเปลี่ยนแปลง 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
พารามิเตอร์ start และ end ของ padding จะเป็นไปตามทิศทางของเลย์เอาต์ หากต้องการเพิ่มระยะห่างจากขอบซ้ายหรือขวาโดยไม่คำนึงถึงทิศทางของเลย์เอาต์ ให้ใช้ absolutePadding พร้อมพารามิเตอร์ left และ right
หากต้องการเพิ่มระยะห่างจากขอบเหนือเส้นบรรทัดข้อความเพื่อให้ได้ระยะห่างที่เฉพาะเจาะจงจากด้านบนของเลย์เอาต์ไปยังเส้นบรรทัด ให้ใช้ตัวแก้ไข 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 - เลื่อนการอ่านออกไปให้นานที่สุด
ความปลอดภัยของขอบเขตใน Compose
ใน Compose มีตัวแก้ไขที่ใช้ได้เฉพาะเมื่อใช้กับคอมโพสิเบิลย่อยบางรายการเท่านั้น 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 จะกำหนดโดยเนื้อหาที่รวมอยู่ คุณสามารถตั้งค่าขนาด Composable ให้ยืดหยุ่นภายในองค์ประกอบหลักได้โดยใช้ตัวแก้ไข weight ซึ่งใช้ได้เฉพาะใน RowScope และ ColumnScope
ลองดู Row ที่มี Composable Box 2 รายการ
กล่องแรกมี weight เป็น 2 เท่าของกล่องที่ 2 จึงมีความกว้างเป็น 2 เท่า เนื่องจาก 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 หลายรายการอาจเป็นประโยชน์ โดยการแยกอินสแตนซ์เหล่านั้นออกเป็นตัวแปรและยกขึ้นไปยังขอบเขตที่สูงขึ้น ซึ่งจะช่วยปรับปรุงความสามารถในการอ่านโค้ดหรือช่วยปรับปรุงประสิทธิภาพของแอปได้ด้วยเหตุผลต่อไปนี้
- ระบบจะไม่จัดสรรตัวแก้ไขซ้ำเมื่อเกิดการจัดองค์ประกอบใหม่สำหรับ Composable ที่ใช้ตัวแก้ไขเหล่านั้น
- เชนตัวแก้ไขอาจยาวและซับซ้อนมาก ดังนั้นการใช้เชนอินสแตนซ์เดียวกันซ้ำจึงช่วยลดภาระงานที่รันไทม์ของ Compose ต้องทำเมื่อเปรียบเทียบเชนได้
- การแยกนี้ช่วยส่งเสริมความสะอาด ความสอดคล้อง และความสามารถในการบำรุงรักษาโค้ดในฐานของโค้ด
แนวทางปฏิบัติแนะนำสำหรับการใช้ตัวแก้ไขซ้ำ
สร้างเชน Modifier ของคุณเองและแยกเชนเหล่านั้นเพื่อนำมาใช้ซ้ำในคอมโพเนนต์ที่ประกอบกันได้หลายรายการ คุณสามารถบันทึกเฉพาะตัวแก้ไขได้ เนื่องจากตัวแก้ไขเป็นออบเจ็กต์ที่คล้ายกับข้อมูล ดังนี้
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 ในกรณีส่วนใหญ่ คุณอาจต้องการให้รายการจำนวนมากที่อาจมีความสำคัญทั้งหมดมีตัวแก้ไขที่เหมือนกันทุกประการ ดังนี้
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 ปิดอยู่
- ข้อมูลเบื้องต้นเกี่ยวกับเลย์เอาต์ Compose
- การดำเนินการของผู้แก้ไข {:#editor-actions}
- เลย์เอาต์ที่กำหนดเอง {:#custom-layouts }