ข้ามไปยังเนื้อหา

Core Layout Widgets

Row กับ Column วาง child ตามแกนเดียว — แนวนอนและแนวตั้ง ทั้งคู่คือ Flex ที่ fix ทิศทางไว้ คุณคุมการจัดตำแหน่งด้วย mainAxisAlignment (ตามแกน) และ crossAxisAlignment (ขวางแกน)

Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // ตามแกนแนวตั้ง
crossAxisAlignment: CrossAxisAlignment.start, // ขวาง (แนวนอน)
children: const [ Text('top'), Text('middle'), Text('bottom') ],
)

Column เป็น unbounded ตามแกนหลักของตัวเองเว้นแต่จะถูก constrain (นึกถึง error ของ ListView จากบทเรียนที่แล้ว) โดย default Column จะ size ตัวเองตาม child (MainAxisSize.max เต็ม, MainAxisSize.min หด)

ใน Row/Column Expanded และ Flexible แบ่งพื้นที่ ที่เหลือ ตาม flex factor นี่คือวิธีสร้าง layout แบบสัดส่วน

Row(
children: [
Expanded(flex: 2, child: blueBox), // ได้ 2/3 ของพื้นที่ว่าง
Expanded(flex: 1, child: redBox), // ได้ 1/3
],
)

ความต่าง: Expanded บังคับให้ child เต็ม ส่วนแบ่งของตัวเอง (constraint แบบ tight) ส่วน Flexible ให้ child ใหญ่ได้ ถึง ส่วนแบ่งแต่ไม่เกิน (แบบ loose) ใช้ Expanded เมื่ออยากให้ child ยืด, ใช้ Flexible เมื่ออยากให้กินไม่เกินส่วนแบ่ง

Stack วาง child ซ้อนทับกัน; Positioned ปักหมุด child ไว้ที่ขอบของ stack นี่คือวิธีสร้าง badge, overlay และการวางตำแหน่งแบบ custom

Stack(
children: [
const Avatar(),
Positioned(
right: 0,
top: 0,
child: const Badge(), // ปักไว้มุมขวาบน
),
],
)

child ที่ไม่ได้ positioned จะ size ตาม stack และจัดตำแหน่งด้วย alignment ของตัวเอง; ตัวที่ positioned จะถูกวางตาม offset ของขอบ

Container เป็นตัวสะดวกที่ ประกอบ widget ง่าย ๆ หลายตัวเข้าด้วยกัน — padding, margin, decoration, constraints, alignment — รวมเป็นตัวเดียว สะดวกก็จริง แต่ข้างในก็แค่ stack ของ Padding, DecoratedBox, ConstrainedBox และ Align

flowchart LR
  container["Container"] --> align["Align"]
  container --> pad["Padding"]
  container --> deco["DecoratedBox"]
  container --> box["ConstrainedBox"]
Container ประกอบขึ้นจาก widget ง่าย ๆ

สำหรับงานเดียว ใช้ widget แบบทำงานเดียวดีกว่า — ชัดกว่าและมักปล่อยให้คุณเก็บ const constructor ไว้ได้:

  • Padding — inset เท่านั้น
  • SizedBox — ขนาดคงที่ (หรือ const SizedBox(height: 8) เป็น spacer ราคาถูก)
  • Center / Align — การวางตำแหน่ง
  • DecoratedBox — background/border เท่านั้น
จริง ๆ แล้ว Row และ Column คืออะไร?
ความต่างระหว่าง Expanded กับ Flexible ใน Row คืออะไร?
จะปักหมุด child ไว้มุมขวาบนของ Stack อย่างไร?
ทำไมควรใช้ Padding หรือ SizedBox แทน Container สำหรับงานเดียว?