Containers & Padding
ใน CSS ทุก HTML element คือกล่องที่มี padding, margin, border, width และ height แต่ Flutter ไม่มี CSS box model แทนที่จะเป็นแบบนั้น มี widget เฉพาะทาง สำหรับแต่ละเรื่อง ตอนแรกฟังดูเหมือนยืดยาว แต่ทำให้เจตนาของ layout ชัดเจนและประกอบกันได้
widget สามตัวที่คุณจะหยิบมาใช้บ่อยที่สุดคือ Container (กล่องครบในตัวเดียว), Padding (เว้นระยะอย่างเดียว) และ SizedBox (ขนาดตายตัวหรือใช้เว้นช่องว่าง)
คำศัพท์เรื่องกล่องของ Flutter
หัวข้อที่มีชื่อว่า “คำศัพท์เรื่องกล่องของ Flutter”| CSS property | Flutter widget / property |
|---|---|
padding: 16px | Padding(padding: EdgeInsets.all(16)) |
padding: 8px 16px | EdgeInsets.symmetric(vertical: 8, horizontal: 16) |
padding: 4px 8px 12px 16px | EdgeInsets.only(top: 4, right: 8, bottom: 12, left: 16) |
margin: 8px | ห่อ parent ด้วย Padding หรือใช้ Container(margin: ...) |
width: 200px; height: 100px | SizedBox(width: 200, height: 100) |
width: 100% | SizedBox(width: double.infinity) |
background-color, border-radius, box-shadow, border | Container(decoration: BoxDecoration(...)) |
width: 200px; background: blue; border-radius: 8px | Container(width: 200, decoration: BoxDecoration(color: Colors.blue, borderRadius: ...)) |
widget กล่องสามตัวและควรใช้ตัวไหนเมื่อไหร่
หัวข้อที่มีชื่อว่า “widget กล่องสามตัวและควรใช้ตัวไหนเมื่อไหร่”Padding ใช้เมื่อคุณต้องการแค่เว้นระยะรอบ child เท่านั้น Padding เบากว่า Container เพราะไม่มีต้นทุนในการวาด (painting cost)
SizedBox ใช้เมื่อคุณต้องการขนาดตายตัว หรือใช้เป็นช่องว่างระหว่าง widget (SizedBox(height: 16) เป็นวิธีเว้นระยะแนวตั้งที่นิยมใช้กัน)
Container ใช้เมื่อคุณต้องการ visual property หลายอย่างพร้อมกัน เช่น color, padding, margin, border, border-radius หรือ shadow อย่าใช้ Container เพียงเพื่อใส่ padding เฉย ๆ ให้ใช้ Padding แทน
ตัวอย่างที่รันได้
หัวข้อที่มีชื่อว่า “ตัวอย่างที่รันได้”import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
appBar: AppBar(title: const Text('Containers & Padding')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16), // Padding on ScrollView
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 16,
children: [
// ------- Padding only -------
const _Label('Padding — all sides 16px'),
Padding(
padding: const EdgeInsets.all(16),
child: Container(color: Colors.blue[100],
child: const Text('Content with padding')),
),
// ------- SizedBox as gap + fixed size -------
const _Label('SizedBox — fixed 200x60'),
Center(
child: SizedBox(
width: 200, height: 60,
child: Container(color: Colors.green[200],
alignment: Alignment.center,
child: const Text('200 x 60')),
),
),
// ------- Container — full box model -------
const _Label('Container — color + border-radius + shadow'),
Container(
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.08),
blurRadius: 10, offset: const Offset(0, 4)),
],
),
child: const Text('This card uses BoxDecoration'),
),
// ------- EdgeInsets.only -------
const _Label('EdgeInsets.only — asymmetric padding'),
Container(
color: Colors.orange[100],
padding: const EdgeInsets.only(
top: 4, right: 8, bottom: 12, left: 24),
child: const Text('top:4 right:8 bottom:12 left:24'),
),
],
),
),
),
);
}
}
class _Label extends StatelessWidget {
final String text;
const _Label(this.text);
@override
Widget build(BuildContext context) => Text(text,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12,
color: Colors.grey));
}