เช่นเดียวกับชุดเครื่องมือ UI อื่นๆ ส่วนใหญ่ Compose จะแสดงผลเฟรมผ่านเฟสที่แตกต่างกันหลายเฟส ตัวอย่างเช่น ระบบ View ของ Android มี 3 เฟสหลักๆ ได้แก่ การวัด เลย์เอาต์ และการวาด Compose มีลักษณะคล้ายกันมาก แต่มีขั้นตอนเพิ่มเติมที่สำคัญ ซึ่งเรียกว่าการเขียนที่จุดเริ่มต้น
เอกสารประกอบของ Compose อธิบายการคอมโพสในการคิดแบบ Compose และสถานะและ Jetpack Compose
เฟรมมี 3 ระยะ
Compose มี 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โดยจะวัดขนาดขององค์ประกอบย่อย (TextComposable 2 รายการ) ก่อน - ระบบจะวัด
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: การเรียบเรียง
การอ่านสถานะภายในฟังก์ชัน @Composable หรือบล็อก Lambda จะส่งผลต่อการจัดองค์ประกอบ
และอาจส่งผลต่อเฟสที่ตามมา เมื่อ value ของสถานะเปลี่ยนแปลง
Recomposer จะกำหนดเวลาให้เรียกใช้ฟังก์ชันที่ประกอบกันได้ทั้งหมดที่อ่าน 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 ที่ใช้ร่วมกันได้ วิธี 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) ขณะที่ผู้ใช้เลื่อน firstVisibleItemScrollOffsetvalue จะเปลี่ยนไป ดังที่ได้ทราบกันไปแล้ว Compose
จะติดตามการอ่านสถานะทั้งหมดเพื่อให้สามารถรีสตาร์ท (เรียกใช้ซ้ำ) โค้ดการอ่านได้
ซึ่งในตัวอย่างนี้คือเนื้อหาของ Box
นี่คือตัวอย่างการอ่านสถานะภายในเฟสการจัดองค์ประกอบ ซึ่งไม่ได้เป็นสิ่งที่ไม่ดีเสมอไป และในความเป็นจริงแล้วเป็นพื้นฐานของการจัดองค์ประกอบใหม่ ที่ช่วยให้การเปลี่ยนแปลงข้อมูลแสดง UI ใหม่ได้
ประเด็นสำคัญ: ตัวอย่างนี้ไม่เหมาะสมเนื่องจากเหตุการณ์การเลื่อนทุกครั้งจะทำให้ระบบประเมินเนื้อหาที่ประกอบได้ทั้งหมดอีกครั้ง วัดผล จัดวาง และสุดท้ายคือวาด คุณจะทริกเกอร์เฟสการเขียนในทุกการเลื่อน แม้ว่าเนื้อหาที่แสดงจะไม่มีการเปลี่ยนแปลง แต่ตำแหน่งมีการเปลี่ยนแปลง คุณสามารถเพิ่มประสิทธิภาพการอ่านสถานะเพื่อ ทริกเกอร์เฟสเลย์เอาต์อีกครั้งเท่านั้น
หักลบด้วยแลมบ์ดา
ตัวปรับออฟเซ็ตอีกเวอร์ชันพร้อมให้ใช้งานแล้ว
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 จะติดตามเมื่อมีการอ่านสถานะ
การเปลี่ยนแปลงนี้จึงหมายความว่าหาก value ของ firstVisibleItemScrollOffset เปลี่ยน
Compose จะต้องรีสตาร์ทเฉพาะขั้นตอนเลย์เอาต์และการวาด
แน่นอนว่าในเฟสการคอมโพส คุณมักจะต้องอ่านสถานะ อย่างไรก็ตาม ในบางกรณี คุณสามารถลดจำนวนการ
จัดองค์ประกอบใหม่ได้โดยการกรองการเปลี่ยนแปลงสถานะ ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่derivedStateOf: แปลงออบเจ็กต์สถานะอย่างน้อย 1 รายการเป็นสถานะอื่น
การวนซ้ำของการจัดองค์ประกอบใหม่ (การขึ้นต่อกันของระยะแบบวนซ้ำ)
ก่อนหน้านี้ คู่มือนี้ระบุว่าเฟสของ Compose จะเรียกใช้ตามลำดับเดียวกันเสมอ และไม่มีวิธีกลับไปก่อนหน้าขณะอยู่ในเฟรมเดียวกัน อย่างไรก็ตาม การดำเนินการดังกล่าวไม่ได้ห้ามไม่ให้แอปเข้าสู่ลูปการคอมโพส ในเฟรมต่างๆ ลองดูตัวอย่างนี้
Box { var imageHeightPx by remember { mutableIntStateOf(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 หลายรายการที่ควรวัดและวางไว้โดยคำนึงถึงกันและกัน การใช้เลย์เอาต์ดั้งเดิมที่เหมาะสมหรือการสร้างเลย์เอาต์ที่กำหนดเองหมายความว่าองค์ประกอบระดับบนสุดที่แชร์กันจะทำหน้าที่เป็นแหล่งข้อมูลที่เชื่อถือได้ ซึ่งสามารถประสานความสัมพันธ์ระหว่างองค์ประกอบหลายรายการได้ การนำสถานะแบบไดนามิกมาใช้จะทำให้หลักการนี้ไม่เป็นจริง
ดูข้อมูลเพิ่มเติมเกี่ยวกับลูปการจัดองค์ประกอบใหม่และวิธีหลีกเลี่ยงการเขียนไปยังสถานะในแต่ละเฟสได้ที่การเขียนย้อนกลับใน Compose
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- สถานะและ Jetpack Compose
- รายการและตารางกริด
- Kotlin สำหรับ Jetpack Compose