ข้อจำกัดและลำดับตัวแก้ไข

ใน Compose คุณสามารถเชื่อมโยงตัวแก้ไขหลายรายการเข้าด้วยกันเพื่อเปลี่ยนรูปลักษณ์ของ Composable ได้ เชนตัวปรับแต่งเหล่านี้อาจส่งผลต่อข้อจำกัดที่ส่งไปยัง Composable ซึ่งกำหนดขอบเขตความกว้างและความสูง

หน้านี้อธิบายว่าตัวปรับแต่งที่เชื่อมโยงส่งผลต่อข้อจำกัดอย่างไร และส่งผลต่อการวัดและการจัดวาง Composable อย่างไร

ตัวแก้ไขในโครงสร้าง UI

เพื่อให้เข้าใจว่าตัวปรับแต่งมีอิทธิพลต่อกันอย่างไร การแสดงภาพลักษณะที่ปรากฏในโครงสร้าง UI ซึ่งสร้างขึ้นในระยะการจัดองค์ประกอบจะช่วยได้ ดูข้อมูลเพิ่มเติมได้ที่ส่วนองค์ประกอบ

ในแผนผัง UI คุณสามารถแสดงภาพตัวแก้ไขเป็นโหนด Wrapper สำหรับโหนดเลย์เอาต์ได้ ดังนี้

โค้ดสำหรับ Composable และตัวแก้ไข รวมถึงการแสดงภาพเป็นแผนผัง UI
รูปที่ 1 ตัวแก้ไขที่รวมโหนดเลย์เอาต์ในแผนผัง UI

การเพิ่มตัวแก้ไขมากกว่า 1 รายการลงใน Composable จะสร้างเชนของตัวแก้ไข เมื่อคุณเชื่อมโยงตัวแก้ไขหลายรายการ โหนดตัวแก้ไขแต่ละโหนดจะรวมส่วนที่เหลือของเชนและโหนดเลย์เอาต์ไว้ภายใน ตัวอย่างเช่น เมื่อคุณเชื่อมโยงตัวแก้ไข clip และ size โหนดตัวแก้ไข clip จะรวมโหนดตัวแก้ไข size ซึ่งจะรวมโหนดเลย์เอาต์ Image อีกที

ในระยะเลย์เอาต์ อัลกอริทึมที่เดินตามต้นไม้จะยังคงเหมือนเดิม แต่ระบบจะเข้าชมโหนดตัวแก้ไขแต่ละโหนดด้วย ด้วยวิธีนี้ ตัวแก้ไขจะเปลี่ยนข้อกำหนดด้านขนาดและตำแหน่งของตัวแก้ไขหรือโหนดเลย์เอาต์ที่รวมอยู่ได้

ดังที่แสดงในรูปที่ 2 การติดตั้งใช้งานคอมโพสิเบิล Image และ Text ประกอบด้วยเชนของตัวแก้ไขที่รวมโหนดเลย์เอาต์เดียว

การติดตั้งใช้งาน Row และ Column เป็นโหนดเลย์เอาต์ที่อธิบายวิธีจัดเลย์เอาต์ขององค์ประกอบย่อย

โครงสร้างต้นไม้จากก่อนหน้านี้ แต่ตอนนี้แต่ละโหนดเป็นเพียงเลย์เอาต์ที่เรียบง่าย โดยมีโหนด Modifier จำนวนมากที่รวมโหนดต่างๆ ไว้รอบๆ
รูปที่ 2 โครงสร้างแบบต้นไม้เดียวกันกับในรูปที่ 1 แต่มี Composable ในแผนผัง UI ที่แสดงเป็นเชนของตัวแก้ไข

สรุปได้ว่า

  • ตัวแก้ไขจะรวมตัวแก้ไขหรือโหนดเลย์เอาต์รายการเดียว
  • โหนดเลย์เอาต์สามารถจัดวางโหนดบุตรหลานได้หลายโหนด

ส่วนต่อไปนี้จะอธิบายวิธีใช้โมเดลทางความคิดนี้เพื่อพิจารณาเกี่ยวกับการเชื่อมโยงตัวปรับแต่งและวิธีที่ตัวปรับแต่งส่งผลต่อขนาดของ Composable

ข้อจำกัดในระยะเลย์เอาต์

ระยะเลย์เอาต์เป็นไปตามอัลกอริทึม 3 ขั้นตอนเพื่อค้นหาความกว้าง ความสูง และพิกัด x, y ของโหนดเลย์เอาต์แต่ละโหนด ดังนี้

  1. วัดโหนดย่อย: โหนดจะวัดโหนดย่อย (หากมี)
  2. กำหนดขนาดของตัวเอง: โหนดจะกำหนดขนาดของตัวเองตามการวัดเหล่านั้น
  3. วางโหนดบุตรหลาน: โหนดบุตรหลานแต่ละโหนดจะวางตามตำแหน่งของโหนดเอง

Constraints ช่วยค้นหาขนาดที่เหมาะสมสำหรับโหนดในระหว่าง 2 ขั้นตอนแรกของอัลกอริทึม ข้อจำกัดจะกำหนดขอบเขตต่ำสุดและสูงสุดสำหรับความกว้างและความสูงของโหนด เมื่อโหนดกำหนดขนาด ขนาดที่วัดได้ควรอยู่ในช่วงขนาดนี้

ประเภทข้อจำกัด

ข้อจำกัดอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้

  • มีขอบเขต: โหนดมีความกว้างและความสูงสูงสุดและต่ำสุด
ข้อจำกัดที่มีขอบเขตของขนาดต่างๆ ภายในคอนเทนเนอร์
รูปที่ 3 ข้อจำกัดที่มีขอบเขต
  • ไม่จำกัด: โหนดไม่มีข้อจำกัดด้านขนาด ขอบเขตความกว้างและความสูงสูงสุดจะตั้งค่าเป็นไม่มีที่สิ้นสุด
ข้อจำกัดที่ไม่มีขอบเขตซึ่งมีความกว้างและความสูงที่ตั้งค่าเป็นค่าอนันต์ ข้อจำกัดขยายออกไปนอกคอนเทนเนอร์
รูปที่ 4 ข้อจำกัดที่ไม่มีขอบเขต
  • Exact: ระบบขอให้โหนดเป็นไปตามข้อกำหนดด้านขนาดที่แน่นอน ขอบเขตต่ำสุดและสูงสุดตั้งค่าเป็นค่าเดียวกัน
ข้อจำกัดที่แน่นอนซึ่งสอดคล้องกับข้อกำหนดด้านขนาดที่แน่นอนภายในคอนเทนเนอร์
รูปที่ 5 ข้อจำกัดที่แน่นอน
  • แบบผสม: โหนดเป็นไปตามข้อจำกัดประเภทต่างๆ ข้างต้นรวมกัน เช่น ข้อจำกัดอาจจำกัดความกว้างในขณะที่อนุญาตให้มีความสูงสูงสุดแบบไม่จำกัด หรือกำหนดความกว้างที่แน่นอนแต่ให้ความสูงที่จำกัด
คอนเทนเนอร์ 2 รายการที่แสดงชุดค่าผสมของข้อจำกัดแบบมีขอบเขตและไม่มีขอบเขต รวมถึงความกว้างและความสูงที่แน่นอน
รูปที่ 6 การผสมผสานระหว่างข้อจำกัดแบบมีขอบเขตและไม่มีขอบเขต รวมถึงความกว้างและความสูงที่แน่นอน

ส่วนถัดไปจะอธิบายวิธีส่งต่อข้อจำกัดเหล่านี้จากระดับบนไปยังระดับล่าง

วิธีส่งต่อข้อจำกัดจากระดับบนไปยังระดับย่อย

ในขั้นตอนแรกของอัลกอริทึมที่อธิบายไว้ในข้อจำกัดในระยะเลย์เอาต์ ระบบจะส่งข้อจำกัดจากระดับบนลงล่างในโครงสร้าง UI

เมื่อโหนดหลักวัดโหนดรอง โหนดหลักจะระบุข้อจำกัดเหล่านี้ให้กับโหนดรองแต่ละโหนดเพื่อให้ทราบว่าโหนดรองมีขนาดใหญ่หรือเล็กได้เพียงใด จากนั้นเมื่อกำหนดขนาดของตัวเอง ก็จะยึดตามข้อจำกัดที่ส่งมาจากองค์ประกอบหลักด้วย

ในระดับสูง อัลกอริทึมจะทำงานในลักษณะต่อไปนี้

  1. โหนดรูทในต้นไม้ UI จะวัดโหนดย่อยและส่งต่อข้อจำกัดเดียวกันไปยังโหนดย่อยแรกเพื่อตัดสินใจขนาดที่ต้องการใช้จริง
  2. หากองค์ประกอบย่อยเป็นตัวแก้ไขที่ไม่ส่งผลต่อการวัด ระบบจะส่งต่อข้อจำกัดไปยังตัวแก้ไขถัดไป ระบบจะส่งข้อจำกัดลงไปตามเชนของตัวแก้ไขตามที่เป็นอยู่ เว้นแต่จะถึงตัวแก้ไขที่ส่งผลต่อการวัด จากนั้นระบบจะปรับขนาดข้อจำกัดตามความเหมาะสม
  3. เมื่อถึงโหนดที่ไม่มีโหนดย่อย (เรียกว่า "โหนดปลายสุด") โหนดจะตัดสินใจขนาดตามข้อจำกัดที่ส่งเข้ามา และแสดงผลขนาดที่แก้ไขแล้วนี้ไปยังโหนดหลัก
  4. วิดเจ็ตหลักจะปรับข้อจำกัดตามการวัดของวิดเจ็ตย่อยนี้ และเรียกใช้วิดเจ็ตย่อยถัดไปโดยใช้ข้อจำกัดที่ปรับแล้วเหล่านี้
  5. เมื่อวัดโหนดย่อยทั้งหมดของโหนดหลักแล้ว โหนดหลักจะกำหนดขนาดของตัวเองและสื่อสารขนาดนั้นไปยังโหนดหลักของตัวเอง
  6. ด้วยวิธีนี้ ระบบจะข้ามผ่านทั้งต้นไม้แบบ Depth-First ในที่สุด โหนดทั้งหมดจะตัดสินใจเลือกขนาดของตนเอง และขั้นตอนการวัดขนาดจะเสร็จสมบูรณ์

ดูตัวอย่างเชิงลึกได้ในวิดีโอข้อจำกัดและลำดับของตัวแก้ไข

ตัวแก้ไขที่มีผลต่อข้อจำกัด

คุณได้เรียนรู้ในส่วนก่อนหน้าแล้วว่าตัวแก้ไขบางตัวอาจส่งผลต่อขนาดข้อจำกัด ส่วนต่อไปนี้จะอธิบายตัวแก้ไขที่เฉพาะเจาะจงซึ่งส่งผลต่อข้อจำกัด

ตัวปรับแต่ง size

ตัวแก้ไข size จะประกาศขนาดที่ต้องการของเนื้อหา

ตัวอย่างเช่น แผนผัง UI ต่อไปนี้ควรแสดงผลในคอนเทนเนอร์ขนาด 300dp คูณ 200dp ข้อจำกัดมีขอบเขต โดยอนุญาตให้มีความกว้างระหว่าง 100dp ถึง 300dp และความสูงระหว่าง 100dp ถึง 200dp ดังนี้

ส่วนหนึ่งของแผนผัง UI ที่มีตัวปรับขนาดที่รวมโหนดเลย์เอาต์ และการแสดงข้อจำกัดที่มีขอบเขตซึ่งกำหนดโดยตัวปรับขนาดในคอนเทนเนอร์
รูปที่ 7 ข้อจำกัดที่มีขอบเขตในโครงสร้าง UI และการแสดงผลในคอนเทนเนอร์

ตัวแก้ไข size จะปรับข้อจำกัดขาเข้าให้ตรงกับค่าที่ส่งมา ในตัวอย่างนี้ ค่าคือ 150dp:

เหมือนกับรูปที่ 7 ยกเว้นว่าตัวปรับขนาดจะปรับข้อจำกัดขาเข้าให้ตรงกับค่าที่ส่งมา
รูปที่ 8 ตัวแก้ไข size กำลังปรับข้อจำกัดเป็น 150dp

หากความกว้างและความสูงมีขนาดเล็กกว่าขอบเขตข้อจำกัดที่เล็กที่สุด หรือใหญ่กว่าขอบเขตข้อจำกัดที่ใหญ่ที่สุด ตัวปรับแต่งจะจับคู่ข้อจำกัดที่ส่งมาให้ใกล้เคียงที่สุดเท่าที่จะทำได้ โดยยังคงยึดตามข้อจำกัดที่ส่งมา ดังนี้

แผนผัง UI 2 รายการและการแสดงผลที่เกี่ยวข้องในคอนเทนเนอร์ ในกรณีแรก ตัวปรับขนาดจะยอมรับข้อจำกัดที่เข้ามา ในกรณีที่ 2 ตัวปรับขนาดจะปรับให้เข้ากับข้อจำกัดที่ใหญ่เกินไปให้ใกล้เคียงที่สุด ส่งผลให้เกิดข้อจำกัดที่เติมเต็มคอนเทนเนอร์
รูปที่ 9 size ตัวแก้ไขที่ยึดตามข้อจำกัดที่ส่งมาอย่างใกล้เคียงที่สุด

โปรดทราบว่าการเชื่อมโยงตัวแก้ไข size หลายรายการจะใช้ไม่ได้ ตัวแก้ไข size ตัวแรกจะตั้งค่าข้อจำกัดทั้งต่ำสุดและสูงสุดเป็นค่าคงที่ แม้ว่าตัวแก้ไขขนาดที่ 2 จะขอขนาดที่เล็กกว่าหรือใหญ่กว่า แต่ก็ยังต้องเป็นไปตามขอบเขตที่แน่นอนที่ส่งเข้ามา ดังนั้นจึงจะไม่ลบล้างค่าเหล่านั้น

เชนของตัวแก้ไขขนาด 2 รายการใน UI Tree และการแสดงผลในคอนเทนเนอร์ ซึ่งเป็นผลลัพธ์ของค่าแรกที่ส่งเข้ามา ไม่ใช่ค่าที่ 2
รูปที่ 10 เชนของตัวแก้ไข size 2 ตัว ซึ่งค่าที่ 2 ที่ส่งเข้ามา (50dp) จะไม่ลบล้างค่าแรก (100dp)

ตัวปรับแต่ง requiredSize

ใช้ตัวแก้ไข requiredSize แทน size หากต้องการให้โหนดลบล้างข้อจำกัดที่เข้ามา ตัวแก้ไข requiredSize จะแทนที่ข้อจำกัดขาเข้าและส่งขนาดที่คุณระบุเป็นขอบเขตที่แน่นอน

เมื่อส่งขนาดกลับขึ้นไปในโครงสร้าง โหนดย่อยจะอยู่ตรงกลางในพื้นที่ว่างที่มีอยู่

ตัวแก้ไข size และ requiredSize ที่ต่อกันในแผนผัง UI และการแสดงผลที่เกี่ยวข้องในคอนเทนเนอร์ ข้อจำกัดของตัวปรับแต่ง requiredSize จะลบล้างข้อจำกัดของตัวปรับแต่ง size
รูปที่ 11 ตัวแก้ไข requiredSize จะลบล้างข้อจำกัดขาเข้าจากตัวแก้ไข size

ตัวแก้ไข width และ height

ตัวแก้ไข size จะปรับทั้งความกว้างและความสูงของข้อจำกัด ตัวแก้ไข width ช่วยให้คุณกำหนดความกว้างคงที่ได้ แต่ไม่ต้องกำหนดความสูง ในทำนองเดียวกัน คุณสามารถใช้ตัวแก้ไข height เพื่อกำหนดความสูงคงที่ แต่ปล่อยให้ความกว้างไม่แน่นอนได้ ดังนี้

แผนผัง UI 2 แผนผัง แผนผังหนึ่งมีตัวแก้ไขความกว้างและการแสดงผลคอนเทนเนอร์ และอีกแผนผังหนึ่งมีตัวแก้ไขความสูงและการแสดงผล
รูปที่ 12 ตัวแก้ไข width และตัวแก้ไข height จะตั้งค่าความกว้างและความสูงคงที่ตามลำดับ

ตัวปรับแต่ง sizeIn

ตัวแก้ไข sizeIn ช่วยให้คุณตั้งค่าข้อจำกัดขั้นต่ำและสูงสุดที่แน่นอนสำหรับความกว้างและความสูงได้ ใช้ตัวปรับแต่ง sizeIn หากต้องการควบคุมข้อจำกัดอย่างละเอียด

แผนผัง UI ที่มีตัวแก้ไข sizeIn ที่ตั้งค่าความกว้างและความสูงขั้นต่ำและสูงสุดไว้ และการแสดงผลภายในคอนเทนเนอร์
รูปที่ 13 ตัวแก้ไข sizeIn ที่มี minWidth, maxWidth, minHeight และ maxHeight ตั้งค่าไว้

ตัวอย่าง

ส่วนนี้จะแสดงและอธิบายเอาต์พุตจากข้อมูลโค้ดหลายรายการที่มีตัวแก้ไขแบบเชน

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

ข้อมูลโค้ดนี้จะสร้างเอาต์พุตต่อไปนี้

สี่เหลี่ยมจัตุรัสสีน้ำเงินที่เติมเต็มคอนเทนเนอร์ระดับบนสุด
รูปที่ 14 Image จะเติมขนาดสูงสุดตามผลลัพธ์ของเชนตัวแก้ไข
  • ตัวแก้ไข fillMaxSize จะเปลี่ยนข้อจำกัดเพื่อตั้งค่าทั้งความกว้างและความสูงขั้นต่ำเป็นค่าสูงสุด ซึ่งก็คือความกว้าง 300dp และความสูง 200dp
  • แม้ว่าตัวแก้ไข size จะต้องการใช้ขนาด 50dp แต่ก็ยังคงต้องปฏิบัติตามข้อจำกัดขั้นต่ำที่เข้ามา ดังนั้นตัวแก้ไข size จะแสดงผลขอบเขตข้อจำกัดที่แน่นอนของ 300 คูณ 200 ด้วย โดยไม่สนใจค่าที่ระบุในตัวแก้ไข size
  • Image จะทำตามขอบเขตเหล่านี้และรายงานขนาด 300 คูณ 200 ซึ่งจะส่งต่อไปยังต้นไม้ทั้งหมด

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

ข้อมูลโค้ดนี้จะสร้างเอาต์พุตต่อไปนี้

สี่เหลี่ยมจัตุรัสสีน้ำเงินขนาดเล็กอยู่ตรงกลางภายในคอนเทนเนอร์หลัก
รูปที่ 15 Image จะอยู่ตรงกลางและมีขนาด 50dp
  • ตัวแก้ไข fillMaxSize จะปรับข้อจำกัดเพื่อตั้งค่าทั้งความกว้างและความสูงขั้นต่ำเป็นค่าสูงสุด ซึ่งก็คือความกว้าง 300dp และความสูง 200dp
  • ตัวแก้ไข wrapContentSize จะรีเซ็ตข้อจำกัดขั้นต่ำ ดังนั้น แม้ว่า fillMaxSize จะส่งผลให้เกิดข้อจำกัดแบบคงที่ แต่ wrapContentSize จะรีเซ็ตกลับเป็นข้อจำกัดแบบมีขอบเขต ตอนนี้โหนดต่อไปนี้จะใช้พื้นที่ทั้งหมดอีกครั้งหรือมีขนาดเล็กกว่าพื้นที่ทั้งหมดก็ได้
  • ตัวแก้ไข size จะตั้งค่าข้อจำกัดเป็นขอบเขตต่ำสุดและสูงสุดของ 50
  • Image จะเปลี่ยนเป็นขนาด 50 คูณ 50 และตัวแก้ไข size จะส่งต่อขนาดนั้น
  • ตัวแก้ไข wrapContentSize มีพร็อพเพอร์ตี้พิเศษ โดยจะนำองค์ประกอบย่อยและวางไว้ตรงกลางของขอบเขตขั้นต่ำที่ใช้ได้ซึ่งส่งผ่านไปยังองค์ประกอบนั้น ขนาดที่สื่อสารกับองค์ประกอบหลักจึงเท่ากับขอบเขตขั้นต่ำที่ส่งเข้ามา

การรวมตัวแก้ไขเพียง 3 ตัวช่วยให้คุณกำหนดขนาดสำหรับ Composable และจัดให้อยู่กึ่งกลางในองค์ประกอบหลักได้

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .clip(CircleShape)
        .padding(10.dp)
        .size(100.dp)
)

ข้อมูลโค้ดนี้จะสร้างเอาต์พุตต่อไปนี้

รูปทรงกลมที่ถูกตัดออกอย่างไม่ถูกต้องเนื่องจากลำดับของตัวแก้ไข
รูปที่ 16 รูปร่างที่ถูกตัดอย่างไม่ถูกต้องเนื่องจากลำดับของตัวแก้ไข
  • ตัวแก้ไข clip ไม่ได้เปลี่ยนข้อจำกัด
  • ตัวแก้ไข padding จะลดข้อจำกัดสูงสุด
  • ตัวแก้ไข size จะตั้งค่าข้อจำกัดทั้งหมดเป็น 100dp
  • Image จะยึดตามข้อจำกัดเหล่านั้นและรายงานขนาดเป็น 100dp คูณ 100dp
  • ตัวปรับแต่ง padding จะเพิ่ม 10dp ในทุกด้านให้กับขนาดที่รายงานโดย Image ดังนั้นเลย์เอาต์ที่มีระยะห่างจากขอบจะรายงานความกว้างและความสูงเป็น 120dp
  • ตอนนี้ในขั้นตอนการวาด ตัวปรับแต่ง clip จะทำงานบน Canvas ขนาด 120dp คูณ 120dp ระบบจะสร้างมาสก์วงกลมขนาดดังกล่าว
  • จากนั้นตัวปรับแต่ง padding จะแทรกเนื้อหาเข้าไป 10dp ในทุกด้าน ซึ่งจะลดขนาด Canvas สำหรับ Image เป็น 100dp คูณ 100dp
  • ระบบจะวาด Image ในแคนวาสขนาดเล็กลงนั้น ระบบจะตัดรูปภาพตามวงกลมเดิมของ 120dp ดังนั้นผลลัพธ์ที่ได้จึงไม่เป็นวงกลม