เช่นเดียวกับชุดเครื่องมือ UI อื่นๆ ส่วนใหญ่ Compose จะแสดงผลเฟรมผ่านเฟสที่แตกต่างกันหลายเฟส ตัวอย่างเช่น ระบบ View ของ Android มี 3 เฟสหลักๆ ได้แก่ การวัด เลย์เอาต์ และการวาด ฟีเจอร์แต่งเพลงมีความคล้ายกันมาก แต่มีขั้นตอนเพิ่มเติมที่สำคัญ ซึ่งเรียกว่าการแต่งเพลงที่จุดเริ่มต้น
เอกสารประกอบของ Compose อธิบายการคอมโพสในการคิดแบบ Compose และ สถานะและ Jetpack Compose
เฟรมมี 3 เฟส
การแต่งเพลงมี 3 ระยะหลักๆ ดังนี้
- องค์ประกอบ: UI ที่จะแสดง Compose จะเรียกใช้ฟังก์ชันที่ประกอบกันได้และ สร้างคำอธิบายของ UI
- เลย์เอาต์: ตำแหน่งที่จะวาง UI ขั้นตอนนี้ประกอบด้วย 2 ขั้นตอน ได้แก่ การวัดผลและการจัดวาง องค์ประกอบเลย์เอาต์จะวัดและวางตัวเอง รวมถึงองค์ประกอบย่อยใดๆ ในพิกัด 2 มิติสำหรับแต่ละโหนดในแผนผังเลย์เอาต์
- การวาด: วิธีการแสดงผล องค์ประกอบ UI จะวาดลงใน Canvas ซึ่งมักจะเป็น หน้าจออุปกรณ์

โดยทั่วไปแล้วลำดับของเฟสเหล่านี้จะเหมือนกัน ซึ่งช่วยให้ข้อมูลไหลไปในทิศทางเดียวจากองค์ประกอบไปยังเลย์เอาต์ ไปยังการวาดเพื่อสร้างเฟรม (หรือที่เรียกว่าการไหลของข้อมูลแบบทิศทางเดียว) BoxWithConstraints
, LazyColumn
และ LazyRow
เป็นข้อยกเว้นที่สำคัญ ซึ่งการจัดวางองค์ประกอบขององค์ประกอบย่อย
จะขึ้นอยู่กับระยะเลย์เอาต์ขององค์ประกอบหลัก
ในเชิงแนวคิด แต่ละเฟสเหล่านี้จะเกิดขึ้นกับทุกเฟรม แต่เพื่อเพิ่มประสิทธิภาพ Compose จะหลีกเลี่ยงการทำงานซ้ำซึ่งจะคำนวณผลลัพธ์เดียวกัน จากอินพุตเดียวกันในทุกเฟส Compose จะข้ามการเรียกใช้ฟังก์ชันที่สามารถคอมโพสได้หากนำผลลัพธ์ก่อนหน้ามาใช้ซ้ำได้ และ Compose UI จะไม่ จัดเลย์เอาต์ใหม่หรือวาดใหม่ทั้งทรีหากไม่จำเป็น Compose จะทำงาน เฉพาะจำนวนขั้นต่ำที่จำเป็นในการอัปเดต UI การเพิ่มประสิทธิภาพนี้เป็นไปได้เนื่องจาก Compose ติดตามการอ่านสถานะภายในเฟสต่างๆ
ทำความเข้าใจระยะต่างๆ
ส่วนนี้จะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับวิธีดำเนินการทั้ง 3 เฟสของ Compose สำหรับ Composable
การเรียบเรียง
ในเฟสการจัดองค์ประกอบ รันไทม์ Compose จะเรียกใช้ฟังก์ชันที่ประกอบกันได้และ เอาต์พุตโครงสร้างแบบต้นไม้ที่แสดงถึง UI โครงสร้าง UI นี้ประกอบด้วย โหนดเลย์เอาต์ที่มีข้อมูลทั้งหมดที่จำเป็นสำหรับเฟสถัดไป ดังที่แสดงในวิดีโอต่อไปนี้
รูปที่ 2 โครงสร้างแบบต้นไม้ที่แสดง UI ของคุณซึ่งสร้างขึ้นในเฟสการจัดองค์ประกอบ
ส่วนย่อยของโค้ดและทรี UI มีลักษณะดังนี้

ในตัวอย่างเหล่านี้ ฟังก์ชันที่ใช้ร่วมกันได้แต่ละฟังก์ชันในโค้ดจะแมปกับโหนดเลย์เอาต์เดียว ในแผนผัง UI ในตัวอย่างที่ซับซ้อนมากขึ้น Composable อาจมีตรรกะและ โฟลว์การควบคุม และสร้างทรีที่แตกต่างกันเมื่อมีสถานะที่ต่างกัน
การจัดวาง
ในเฟสเลย์เอาต์ Compose จะใช้ทรี UI ที่สร้างขึ้นในเฟสการจัดองค์ประกอบ เป็นอินพุต การรวบรวมโหนดเลย์เอาต์จะมีข้อมูลทั้งหมดที่จำเป็นต่อการ กำหนดขนาดและตำแหน่งของแต่ละโหนดในพื้นที่ 2 มิติ
รูปที่ 4 การวัดและการจัดวางโหนดเลย์เอาต์แต่ละรายการในแผนผัง UI ในระหว่างระยะเลย์เอาต์
ในระหว่างเฟสเลย์เอาต์ ระบบจะข้ามผ่านทรีโดยใช้อัลกอริทึม 3 ขั้นตอนต่อไปนี้
- วัดผลเด็ก: โหนดจะวัดผลรายการย่อยหากมี
- กำหนดขนาดเอง: โหนดจะกำหนดขนาดของตัวเองตามการวัดเหล่านี้
- วางตำแหน่งองค์ประกอบย่อย: โหนดย่อยแต่ละโหนดจะวางตำแหน่งเทียบกับตำแหน่งของโหนดเอง
เมื่อสิ้นสุดระยะนี้ โหนดเลย์เอาต์แต่ละโหนดจะมีสิ่งต่อไปนี้
- ความกว้างและความสูงที่กำหนด
- พิกัด x, y ที่ควรวาด
โปรดระลึกถึงแผนผัง UI จากส่วนก่อนหน้า
สำหรับแผนผังนี้ อัลกอริทึมจะทำงานดังนี้
Row
จะวัดองค์ประกอบย่อยImage
และColumn
- ระบบจะวัด
Image
โดยไม่มีองค์ประกอบย่อย จึงกำหนดขนาดของตัวเองและรายงานขนาดกลับไปยังRow
- จากนั้นจะวัด
Column
โดยจะวัดขนาดขององค์ประกอบย่อย (Composable 2 รายการ) ก่อนText
- ระบบจะวัด
Text
แรก โดยไม่มีองค์ประกอบย่อย จึงกำหนดขนาดของตัวเองและรายงานขนาดกลับไปยังColumn
- ระบบจะวัด
Text
ที่ 2 ไม่มีองค์ประกอบย่อย จึงกำหนดขนาดของตัวเองและรายงานกลับไปยังColumn
- ระบบจะวัด
Column
ใช้การวัดขนาดของเด็กเพื่อกำหนดขนาดของตัวเอง โดยจะใช้ ความกว้างสูงสุดขององค์ประกอบย่อยและผลรวมของความสูงขององค์ประกอบย่อยColumn
จะวางวิดเจ็ตย่อยไว้เทียบกับตัวมันเอง โดยวางวิดเจ็ตย่อยไว้ใต้ กันในแนวตั้งRow
ใช้การวัดขนาดของเด็กเพื่อกำหนดขนาดของตัวเอง โดยจะใช้ ความสูงสูงสุดขององค์ประกอบย่อยและผลรวมของความกว้างขององค์ประกอบย่อย จากนั้นจะ วางองค์ประกอบย่อย
โปรดทราบว่าระบบจะเข้าชมแต่ละโหนดเพียงครั้งเดียว รันไทม์ของ Compose ต้องการเพียง การส่งผ่านต้นไม้ UI เพียงครั้งเดียวเพื่อวัดและวางโหนดทั้งหมด ซึ่งจะช่วยปรับปรุง ประสิทธิภาพ เมื่อจำนวนโหนดในทรีเพิ่มขึ้น เวลาที่ใช้ในการ สำรวจทรีจะเพิ่มขึ้นในลักษณะเชิงเส้น ในทางตรงกันข้าม หากมีการเข้าชมแต่ละโหนดหลายครั้ง เวลาในการข้ามจะเพิ่มขึ้นแบบทวีคูณ
ภาพวาด
ในระยะการวาดภาพ ระบบจะข้ามผ่านทรีอีกครั้งจากบนลงล่าง และแต่ละ โหนดจะวาดตัวเองบนหน้าจอตามลำดับ
รูปที่ 5 ระยะการวาดจะวาดพิกเซลบนหน้าจอ
จากตัวอย่างก่อนหน้า เนื้อหาของแผนผังจะวาดในลักษณะต่อไปนี้
Row
จะวาดเนื้อหาใดๆ ที่อาจมี เช่น สีพื้นหลังImage
จะวาดตัวเองColumn
จะวาดตัวเองText
ตัวแรกและตัวที่ 2 จะวาดตัวเองตามลำดับ
รูปที่ 6 แผนผัง UI และการแสดงผลที่วาด
การอ่านสถานะ
เมื่อคุณอ่าน value
ของ snapshot state
ในช่วงใดช่วงหนึ่ง
ที่ระบุไว้ก่อนหน้านี้ Compose จะติดตามสิ่งที่กำลังทำอยู่โดยอัตโนมัติเมื่ออ่าน
value
การติดตามนี้ช่วยให้ Compose เรียกใช้โปรแกรมอ่านอีกครั้งได้เมื่อvalue
ของสถานะมีการเปลี่ยนแปลง และเป็นพื้นฐานของการสังเกตสถานะใน Compose
โดยปกติแล้ว คุณจะสร้างสถานะโดยใช้ mutableStateOf()
จากนั้นเข้าถึงสถานะผ่าน
วิธีใดวิธีหนึ่งจาก 2 วิธี ได้แก่ การเข้าถึงพร็อพเพอร์ตี้ value
โดยตรง หรือใช้ตัวแทนพร็อพเพอร์ตี้ Kotlin
อ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในสถานะใน
Composable สำหรับวัตถุประสงค์ของคู่มือนี้ "การอ่านสถานะ" หมายถึงวิธีการเข้าถึงที่เทียบเท่ากันอย่างใดอย่างหนึ่ง
// State read without property delegate. val paddingState: MutableState<Dp> = remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(paddingState.value) )
// State read with property delegate. var padding: Dp by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(padding) )
ภายใต้ตัวแทนพร็อพเพอร์ตี้ จะมีการใช้ฟังก์ชัน "getter" และ "setter"
เพื่อเข้าถึงและอัปเดต value
ของสถานะ ฟังก์ชัน Getter และ Setter เหล่านี้จะเรียกใช้เมื่อคุณอ้างอิงพร็อพเพอร์ตี้เป็นค่าเท่านั้น
และจะไม่เรียกใช้เมื่อมีการสร้างพร็อพเพอร์ตี้ ซึ่งเป็นเหตุผลที่ 2 วิธีที่อธิบายไว้ก่อนหน้านี้
จึงเทียบเท่ากัน
บล็อกโค้ดแต่ละบล็อกที่เรียกใช้ซ้ำได้เมื่อสถานะการอ่านเปลี่ยนแปลงคือขอบเขตการรีสตาร์ท Compose จะติดตามการเปลี่ยนแปลงสถานะ value
และขอบเขตการรีสตาร์ท
ในระยะต่างๆ
การอ่านสถานะแบบเป็นระยะ
ดังที่กล่าวไว้ก่อนหน้านี้ Compose มี 3 เฟสหลัก และ Compose จะติดตามสถานะที่อ่านภายในแต่ละเฟส ซึ่งจะช่วยให้ Compose แจ้งเตือน เฉพาะเฟสที่ต้องทำงานสำหรับองค์ประกอบที่ได้รับผลกระทบแต่ละรายการของ UI
ส่วนต่อไปนี้จะอธิบายแต่ละเฟสและสิ่งที่เกิดขึ้นเมื่ออ่านค่าสถานะภายในเฟส
ระยะที่ 1: การเรียบเรียง
การอ่านสถานะภายในบล็อกฟังก์ชันหรือบล็อก Lambda จะส่งผลต่อการคอมโพส
และอาจส่งผลต่อเฟสต่อๆ ไป@Composable
เมื่อ value
ของสถานะมีการเปลี่ยนแปลง
ตัวจัดกำหนดการการจัดองค์ประกอบใหม่จะกำหนดเวลาให้ฟังก์ชันที่สามารถเขียนได้ทั้งหมดซึ่งอ่าน value
ของสถานะนั้นทำงานอีกครั้ง โปรดทราบว่ารันไทม์อาจข้ามฟังก์ชันที่ใช้ร่วมกันได้บางส่วนหรือทั้งหมด หากอินพุตไม่มีการเปลี่ยนแปลง
ดูข้อมูลเพิ่มเติมได้ที่ข้ามหากอินพุตไม่มีการเปลี่ยนแปลง
UI ของ Compose จะเรียกใช้เลย์เอาต์และขั้นตอนการวาดภาพ ทั้งนี้ขึ้นอยู่กับผลลัพธ์ของการจัดองค์ประกอบ ระบบอาจข้ามขั้นตอนเหล่านี้หากเนื้อหายังคงเหมือนเดิมและขนาด และเลย์เอาต์จะไม่เปลี่ยนแปลง
var padding by remember { mutableStateOf(8.dp) } Text( text = "Hello", // The `padding` state is read in the composition phase // when the modifier is constructed. // Changes in `padding` will invoke recomposition. modifier = Modifier.padding(padding) )
ระยะที่ 2: เลย์เอาต์
ระยะเลย์เอาต์ประกอบด้วย 2 ขั้นตอน ได้แก่ การวัดและการวาง
ขั้นตอนการวัดจะเรียกใช้ Lambda การวัดที่ส่งไปยังเมธอด Layout
composable
MeasureScope.measure
ของอินเทอร์เฟซ LayoutModifier
และอื่นๆ
ขั้นตอนการจัดตำแหน่งจะเรียกใช้บล็อกการจัดตำแหน่งของฟังก์ชัน layout
, บล็อก Lambda ของ Modifier.offset { … }
และฟังก์ชันที่คล้ายกัน
การอ่านสถานะในแต่ละขั้นตอนเหล่านี้จะส่งผลต่อเลย์เอาต์และอาจส่งผลต่อ
เฟสการวาด เมื่อสถานะของ value
เปลี่ยนแปลง UI ของ Compose จะกำหนดเวลาเลย์เอาต์
เฟส นอกจากนี้ยังเรียกใช้เฟสการวาดหากมีการเปลี่ยนแปลงขนาดหรือตำแหน่ง
var offsetX by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.offset { // The `offsetX` state is read in the placement step // of the layout phase when the offset is calculated. // Changes in `offsetX` restart the layout. IntOffset(offsetX.roundToPx(), 0) } )
ระยะที่ 3: การวาด
การอ่านสถานะระหว่างโค้ดการวาดจะส่งผลต่อเฟสการวาด ตัวอย่างที่พบบ่อย
ได้แก่ Canvas()
, Modifier.drawBehind
และ Modifier.drawWithContent
เมื่อvalue
ของสถานะเปลี่ยนแปลง UI ของ Compose จะเรียกใช้เฉพาะเฟสการวาด
var color by remember { mutableStateOf(Color.Red) } Canvas(modifier = modifier) { // The `color` state is read in the drawing phase // when the canvas is rendered. // Changes in `color` restart the drawing. drawRect(color) }
การอ่านสถานะการเพิ่มประสิทธิภาพ
เนื่องจาก Compose ติดตามการอ่านสถานะที่แปลแล้ว คุณจึงลดปริมาณงานที่ทำได้โดยการอ่านแต่ละสถานะในเฟสที่เหมาะสม
ลองดูตัวอย่างต่อไปนี้ ตัวอย่างนี้มี Image()
ซึ่งใช้ตัวแก้ไขออฟเซ็ตเพื่อชดเชยตำแหน่งเลย์เอาต์สุดท้าย จึงทำให้เกิดเอฟเฟกต์พารัลแลกซ์เมื่อผู้ใช้เลื่อน
Box { val listState = rememberLazyListState() Image( // ... // Non-optimal implementation! Modifier.offset( with(LocalDensity.current) { // State read of firstVisibleItemScrollOffset in composition (listState.firstVisibleItemScrollOffset / 2).toDp() } ) ) LazyColumn(state = listState) { // ... } }
โค้ดนี้ใช้งานได้ แต่จะทำให้ประสิทธิภาพไม่เป็นไปตามที่ต้องการ โค้ดที่เขียนจะ
อ่าน value
ของสถานะ firstVisibleItemScrollOffset
และส่งไปยัง
ฟังก์ชัน Modifier.offset(offset: Dp)
ขณะที่ผู้ใช้เลื่อน firstVisibleItemScrollOffset
value
จะเปลี่ยนไป ดังที่ได้ทราบแล้ว Compose
จะติดตามการอ่านสถานะทั้งหมดเพื่อให้สามารถรีสตาร์ท (เรียกใช้ซ้ำ) โค้ดการอ่าน
ซึ่งในตัวอย่างนี้คือเนื้อหาของ Box
นี่คือตัวอย่างการอ่านสถานะภายในเฟสการจัดองค์ประกอบ ซึ่งไม่ได้เป็นสิ่งที่ไม่ดีเสมอไป และในความเป็นจริงแล้วเป็นพื้นฐานของการจัดองค์ประกอบใหม่ ที่ช่วยให้การเปลี่ยนแปลงข้อมูลแสดง UI ใหม่ได้
ประเด็นสำคัญ: ตัวอย่างนี้ไม่เหมาะสมเนื่องจากเหตุการณ์การเลื่อนทุกครั้งจะส่งผลให้ระบบประเมินเนื้อหาที่ประกอบได้ทั้งหมดอีกครั้ง วัด จัดวาง และสุดท้ายคือวาด คุณจะทริกเกอร์เฟส Compose ทุกครั้งที่เลื่อน แม้ว่าเนื้อหาที่แสดงจะไม่มีการเปลี่ยนแปลง แต่ตำแหน่งมีการเปลี่ยนแปลง คุณสามารถเพิ่มประสิทธิภาพการอ่านสถานะเพื่อ ทริกเกอร์เฉพาะเฟสเลย์เอาต์ได้
ออฟเซ็ตด้วย Lambda
ตัวแก้ไขออฟเซ็ตอีกเวอร์ชันพร้อมใช้งานแล้ว
Modifier.offset(offset: Density.() -> IntOffset)
เวอร์ชันนี้ใช้พารามิเตอร์ Lambda ซึ่งบล็อก Lambda จะแสดงผลออฟเซ็ตที่ได้ อัปเดตรหัสเพื่อใช้งาน
Box { val listState = rememberLazyListState() Image( // ... Modifier.offset { // State read of firstVisibleItemScrollOffset in Layout IntOffset(x = 0, y = listState.firstVisibleItemScrollOffset / 2) } ) LazyColumn(state = listState) { // ... } }
แล้วทำไมวิธีนี้จึงมีประสิทธิภาพมากกว่า บล็อก Lambda ที่คุณระบุให้กับตัวแก้ไขจะเรียกใช้ในระหว่างเฟสเลย์เอาต์ (โดยเฉพาะในระหว่างขั้นตอนการจัดวางของเฟสเลย์เอาต์) ซึ่งหมายความว่าจะไม่มีการอ่านสถานะ firstVisibleItemScrollOffset
ในระหว่างการจัดองค์ประกอบอีกต่อไป เนื่องจาก Compose จะติดตามเมื่อมีการอ่านสถานะ
การเปลี่ยนแปลงนี้จึงหมายความว่าหาก firstVisibleItemScrollOffset
ของ value
เปลี่ยนแปลง
Compose จะต้องรีสตาร์ทเฉพาะเลย์เอาต์และขั้นตอนการวาด
แน่นอนว่าในเฟสการเขียนคอมโพส คุณมักจะต้องอ่านสถานะ อย่างไรก็ตาม ในบางกรณี คุณสามารถลดจำนวนการ
จัดองค์ประกอบใหม่ได้โดยการกรองการเปลี่ยนแปลงสถานะ ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่derivedStateOf
: แปลงออบเจ็กต์สถานะอย่างน้อย 1 รายการเป็นสถานะอื่น
วงจรการจัดองค์ประกอบใหม่ (การขึ้นต่อกันของระยะแบบวนซ้ำ)
ก่อนหน้านี้คู่มือนี้ได้กล่าวถึงว่าเฟสของ Compose จะเรียกใช้ตามลำดับเดียวกันเสมอ และไม่มีวิธีกลับไปก่อนหน้าขณะอยู่ในเฟรมเดียวกัน อย่างไรก็ตาม การดำเนินการดังกล่าวไม่ได้ห้ามไม่ให้แอปเข้าสู่ลูปการเขียน ในเฟรมต่างๆ ลองดูตัวอย่างนี้
Box { var imageHeightPx by remember { mutableStateOf(0) } Image( painter = painterResource(R.drawable.rectangle), contentDescription = "I'm above the text", modifier = Modifier .fillMaxWidth() .onSizeChanged { size -> // Don't do this imageHeightPx = size.height } ) Text( text = "I'm below the image", modifier = Modifier.padding( top = with(LocalDensity.current) { imageHeightPx.toDp() } ) ) }
ตัวอย่างนี้ใช้คอลัมน์แนวตั้ง โดยมีรูปภาพอยู่ด้านบนและข้อความอยู่ด้านล่าง
โดยใช้ Modifier.onSizeChanged()
เพื่อรับขนาดที่แก้ไขแล้ว
ของรูปภาพ จากนั้นใช้ Modifier.padding()
กับข้อความเพื่อเลื่อนลง
การแปลงจาก Px
เป็น Dp
ที่ไม่เป็นธรรมชาติแสดงให้เห็นแล้วว่าโค้ดมีปัญหา
ปัญหาของตัวอย่างนี้คือโค้ดไม่ถึงเลย์เอาต์ "สุดท้าย" ภายในเฟรมเดียว โค้ดต้องอาศัยหลายเฟรมที่เกิดขึ้น ซึ่งทำให้เกิดการทำงานที่ไม่จำเป็นและส่งผลให้ UI กระโดดไปมาบนหน้าจอสำหรับ ผู้ใช้
การจัดวางองค์ประกอบของเฟรมแรก
ในระหว่างเฟสการเรียบเรียงของเฟรมแรก imageHeightPx
จะมีค่าเริ่มต้นเป็น
0
ดังนั้น โค้ดจึงให้ข้อความที่มี Modifier.padding(top = 0)
เฟสเลย์เอาต์ถัดไปจะเรียกใช้onSizeChanged
โค้ดเรียกกลับของตัวแก้ไข
ซึ่งจะอัปเดต imageHeightPx
เป็นความสูงจริงของรูปภาพ จากนั้นจะกำหนดเวลาการจัดองค์ประกอบใหม่สำหรับเฟรมถัดไป อย่างไรก็ตาม ในระหว่าง
ระยะการวาดภาพปัจจุบัน ข้อความจะแสดงผลโดยมีระยะขอบเป็น 0
เนื่องจากค่า imageHeightPx
ที่อัปเดตแล้วยังไม่แสดง
การจัดวางเฟรมที่ 2
Compose จะเริ่มต้นเฟรมที่ 2 ซึ่งทริกเกอร์โดยการเปลี่ยนแปลงค่าของ imageHeightPx
ในระยะการจัดองค์ประกอบของเฟรมนี้ ระบบจะอ่านสถานะภายในBox
บล็อกเนื้อหา ตอนนี้ข้อความมีระยะขอบที่ตรงกับความสูงของรูปภาพอย่างแม่นยำ
ในระหว่างเฟสเลย์เอาต์ ระบบจะตั้งค่า imageHeightPx
อีกครั้ง แต่
จะไม่มีการกำหนดเวลาการจัดองค์ประกอบใหม่เพิ่มเติมเนื่องจากค่าจะยังคงสอดคล้องกัน
ตัวอย่างนี้อาจดูเหมือนจงใจ แต่โปรดระวังรูปแบบทั่วไปนี้
Modifier.onSizeChanged()
,onGloballyPositioned()
หรือการดำเนินการเลย์เอาต์อื่นๆ- อัปเดตสถานะบางอย่าง
- ใช้สถานะนั้นเป็นอินพุตสำหรับตัวแก้ไขเลย์เอาต์ (
padding()
,height()
หรือคล้ายกัน) - อาจทำซ้ำ
การแก้ไขตัวอย่างก่อนหน้าคือการใช้เลย์เอาต์ดั้งเดิมที่เหมาะสม
ตัวอย่างก่อนหน้าสามารถใช้กับ Column()
ได้ แต่คุณอาจมีตัวอย่างที่ซับซ้อนกว่า
ซึ่งต้องใช้สิ่งต่างๆ ที่กำหนดเอง ซึ่งจะต้องเขียนเลย์เอาต์ที่กำหนดเอง ดูข้อมูลเพิ่มเติมได้ในคู่มือเลย์เอาต์ที่กำหนดเอง
หลักการทั่วไปที่นี่คือการมีแหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียวสำหรับองค์ประกอบ UI หลายรายการที่ควรวัดและวางไว้โดยคำนึงถึงกันและกัน การใช้เลย์เอาต์ดั้งเดิมที่เหมาะสมหรือการสร้างเลย์เอาต์ที่กำหนดเองหมายความว่าองค์ประกอบระดับบนสุดที่แชร์กันน้อยที่สุดจะทำหน้าที่เป็นแหล่งข้อมูลที่เชื่อถือได้ ซึ่งสามารถประสานความสัมพันธ์ระหว่างองค์ประกอบหลายรายการได้ การนำสถานะแบบไดนามิกมาใช้จะขัดกับหลักการนี้
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- สถานะและ Jetpack Compose
- รายการและตารางกริด
- Kotlin สำหรับ Jetpack Compose