Constraint Layout - Constrained Width/Height
ใน ConstraintLayout จะมี XML Attribute ให้ใช้งานค่อนข้างเยอะ เพื่อให้ตอบโจทย์กับการสร้าง UI ได้หลากหลายมากที่สุดเท่าที่ทำได้ ซึ่งมีทั้ง Attribute ที่มีให้ตั้งแต่แรกและ Attribute ที่เพิ่มเข้ามาในภายหลังเพื่อเพิ่มความสามารถของ ConstraintLayout ให้มากกว่าเดิม
และในบทความนี้ก็จะมาแนะนำให้รู้จักกับ Attribute ที่ชื่อว่า layout_constrainedWidth
กับ layout_constrainedHeight
ที่ถูกเพิ่มเข้ามาในเวอร์ชัน 1.1 และอาจจะไม่ค่อยคุ้นตากันซักเท่าไร
เกิดมาสำหรับ View ที่กำหนดขนาดด้วย Wrap Content
อย่างที่เรารู้กันว่าเวลากำหนดให้ View มีขนาดเป็น Wrap Content จะทำให้มีขนาดเท่ากับ Wrap Content เสมอ
แต่ถ้า Content นั้น ๆ เกิด Overflow ขึ้นมา ขนาดสูงสุดที่เป็นไปได้สำหรับ Wrap Content จะมีค่าเท่าไรกันนะ?
ซึ่งคำตอบนี้มีหลายคำตอบ โดยขึ้นอยู่กับว่า View ตัวนั้นอยู่ใน Layout ตัวไหน และคำตอบสำหรับ ConstraintLayout ก็คือ "ขนาดสูงสุดเป็นไปได้จะเท่ากับขนาดของ ConstraintLayout"
ยกตัวอย่างเช่น เจ้าของบล็อกสร้าง TextView ที่มีความกว้างเป็น Wrap Content และมีเส้น Constraint ที่เชื่อมกับ ImageView ด้านข้างทั้ง 2 ฝั่ง
จะเห็นว่าเมื่อเกิด Overflow ขึ้น จะทำให้ความกว้างของ TextView ขยายโดยไม่สนใจเส้น Constraint ทำให้ View ขยายความกว้างจน Overlap กับ ImageView
โดยปกติจะแก้ปัญหาแบบนี้ด้วยการใช้ความกว้างเป็น 0dp แทน แต่ถ้าจำเป็นต้องใช้ Wrap Content ก็ให้กำหนด layout_constainedWidth="true"
เพิ่มเข้าไป ซึ่งจะได้ผลลัพธ์ที่เหมือนกัน
layout_constrainedWidth
ใช้กับความกว้างของ Viewlayout_constrainedHeight
ใช้กับแนวความสูงของ View
แล้วทำไมไม่ใช้เป็น 0dp ไปเลยล่ะ?
สำหรับ UI ที่ยกตัวอย่างในก่อนหน้านี้ ผู้ที่หลงเข้ามาอ่านส่วนใหญ่ก็คงตัดสินใจใช้ 0dp แทน เพราะดูเหมาะสมกว่า ดังนั้นมาดูกรณีที่จำเป็นต้องใช้ Wrap Content กัน
จากภาพตัวอย่างข้างบนจะมี TextView 2 ตัวที่เรียงต่อกันแบบชิดซ้ายมือ และมี ImageView อยู่ชิดขวามือตลอดเวลา โดยมีเงื่อนไขว่า ถ้าข้อความใน TextView ตัวแรกเกิด Overflow จะต้องตัดคำให้เป็นเครื่องหมายจุดแทน (Single Line) และ TextView ตัวที่ 2 จะต้องถูกดันจนชิดกับ ImageView
ซึ่งแน่นอนว่า UI ในรูปแบบนี้จะไม่สามารถกำหนดค่าด้วย 0dp ได้เลย เพราะโจทย์ต้องการให้ TextView ทั้ง 2 ตัวอยู่ชิดซ้ายตลอดเวลา จึงต้องใช้ Wrap Content แทน และใช้ layout_constrainedWidth
เข้ามาช่วย โดยใช้ร่วมกับ layout_constraintHorizontal_chainStyle
และ layout_constraintHorizontal_bias
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:padding="16dp">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="Mountain View"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/textView2"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Since 2004"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/space"
app:layout_constraintStart_toEndOf="@id/textView1"
app:layout_constraintTop_toTopOf="parent" />
<Space
android:id="@+id/space"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/imageView"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView"
android:layout_width="60dp"
android:layout_height="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
นอกจากนี้ยังต้องใช้ <space>
เพื่อช่วยดันให้ TextView ทั้ง 2 ตัวชิดซ้ายด้วย
ถ้าไม่กำหนด layout_constrainWidth="true"
จะทำให้ TextView ตัวแรกขยายตามข้อความข้างในจนดัน TextView ตัวที่สองจน Overlap กับ ImageView และล้นออกขอบจอนั่นเอง
สรุป
การใช้ Wrap Content กับ View ที่อยู่ใน ConstraintLayout จะทำให้ View ตัวนั้นสามารถขยายขนาดได้จนเท่ากับขนาดของ ConstraintLayout โดยไม่สนใจว่ากำหนดเส้น Constraint แบบไหนอยู่
แต่การกำหนด layout_constrainedWidth
และ layout_constrainedHeight
เพิ่มเข้าไปจะช่วยให้ View ตัวนั้น ๆ ขยายขนาดโดยอ้างอิงจากการเชื่อมเส้น Constraint กับ View ตัวอื่น ๆ ด้วย ทำให้ขอบเขตในการขยายที่สามารถเกิดขึ้นได้จะเหมือนกับการใช้ 0dp
ในการใช้ Wrap Content ร่วมกับ layout_constrainedWidth
และ layout_constrainedHeight
จะเหมาะกับ UI บางรูปแบบเท่านั้น ดังนั้นกรณีทั่วไปก็แนะนำให้ใช้เป็น 0dp แทนเพื่อความง่ายและรวดเร็ว