Core Layout Widgets
Row, Column และ Flex
หัวข้อที่มีชื่อว่า “Row, Column และ Flex”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 หด)
Expanded และ Flexible: แบ่งพื้นที่ว่าง
หัวข้อที่มีชื่อว่า “Expanded และ Flexible: แบ่งพื้นที่ว่าง”ใน 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 และ Positioned: child ที่ซ้อนกัน
หัวข้อที่มีชื่อว่า “Stack และ Positioned: child ที่ซ้อนกัน”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 และตัวช่วยแบบทำงานเดียว
หัวข้อที่มีชื่อว่า “Container และตัวช่วยแบบทำงานเดียว”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"]
สำหรับงานเดียว ใช้ widget แบบทำงานเดียวดีกว่า — ชัดกว่าและมักปล่อยให้คุณเก็บ const constructor ไว้ได้:
Padding— inset เท่านั้นSizedBox— ขนาดคงที่ (หรือconst SizedBox(height: 8)เป็น spacer ราคาถูก)Center/Align— การวางตำแหน่งDecoratedBox— background/border เท่านั้น