Bỏ qua để đến nội dung

📏 Padding & Margin

Tạo khoảng cách bên trong widget:

Padding(
padding: EdgeInsets.all(16),
child: Text('Padded Text'),
)

// Tất cả các cạnh
EdgeInsets.all(16)
// Chỉ định từng cạnh
EdgeInsets.only(left: 10, top: 20, right: 10, bottom: 20)
// Đối xứng
EdgeInsets.symmetric(horizontal: 20, vertical: 10)
// LTRB (Left, Top, Right, Bottom)
EdgeInsets.fromLTRB(10, 20, 10, 20)
// Zero
EdgeInsets.zero

Container có property margin cho khoảng cách bên ngoài:

Container(
margin: EdgeInsets.all(16),
padding: EdgeInsets.all(8),
color: Colors.blue,
child: Text('Content'),
)

Container(
margin: EdgeInsets.all(10), // Khoảng cách NGOÀI border
padding: EdgeInsets.all(10), // Khoảng cách TRONG border
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: Text('Content'),
)
┌─────────────────────────────┐
│ MARGIN │
│ ┌───────────────────┐ │
│ │ BORDER │ │
│ │ ┌─────────────┐ │ │
│ │ │ PADDING │ │ │
│ │ │ ┌─────────┐ │ │ │
│ │ │ │ CONTENT │ │ │ │
│ │ │ └─────────┘ │ │ │
│ │ └─────────────┘ │ │
│ └───────────────────┘ │
└─────────────────────────────┘

Thay vì Padding, dùng SizedBox cho spacing giữa widgets:

Column(
children: [
Text('Title'),
SizedBox(height: 16), // Spacing dọc
Text('Subtitle'),
SizedBox(height: 8),
Text('Content'),
],
)
Row(
children: [
Icon(Icons.star),
SizedBox(width: 8), // Spacing ngang
Text('Rating'),
],
)

Chiếm không gian còn lại (giống Expanded nhưng không có child):

Row(
children: [
Text('Left'),
Spacer(), // Đẩy ra hai bên
Text('Right'),
],
)
// Với flex
Row(
children: [
Text('Left'),
Spacer(flex: 1),
Text('Center'),
Spacer(flex: 2), // Gấp đôi không gian bên trái
Text('Right'),
],
)

Tránh notch, status bar, navigation bar:

SafeArea(
child: Column(
children: [
Text('Safe content'),
],
),
)
SafeArea(
top: true,
bottom: false,
left: true,
right: true,
child: Content(),
)

Lấy system padding thủ công:

@override
Widget build(BuildContext context) {
final padding = MediaQuery.of(context).padding;
return Padding(
padding: EdgeInsets.only(top: padding.top),
child: Content(),
);
}

Trong CustomScrollView:

CustomScrollView(
slivers: [
SliverPadding(
padding: EdgeInsets.all(16),
sliver: SliverList(...),
),
],
)

class AppSpacing {
static const xs = 4.0;
static const sm = 8.0;
static const md = 16.0;
static const lg = 24.0;
static const xl = 32.0;
}
// Sử dụng
Padding(
padding: EdgeInsets.all(AppSpacing.md),
child: Text('Consistent'),
)
Scaffold(
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
// Content không cần padding riêng
],
),
),
)

Widget/Property Mục đích
Padding Khoảng cách bên trong
Container.margin Khoảng cách bên ngoài
SizedBox Spacing cố định
Spacer Chiếm không gian còn lại
SafeArea Tránh system UI
EdgeInsets Mô tả
.all(x) Tất cả cạnh
.symmetric() Đối xứng
.only() Chỉ định từng cạnh
.fromLTRB() Left, Top, Right, Bottom