📐 Constraints
1. Nguyên tắc cốt lõi
Phần tiêu đề “1. Nguyên tắc cốt lõi”Flutter layout tuân theo quy tắc đơn giản nhưng rất quan trọng:
“Constraints go down. Sizes go up. Parent sets position.”
(Constraints đi xuống. Kích thước đi lên. Parent đặt vị trí.)
2. Constraints là gì?
Phần tiêu đề “2. Constraints là gì?”Constraints định nghĩa kích thước tối thiểu và tối đa mà một widget có thể có:
BoxConstraints( minWidth: 0, maxWidth: 300, minHeight: 0, maxHeight: 200,)3. Quy trình Layout
Phần tiêu đề “3. Quy trình Layout”┌─────────────────────────────────────────┐│ 1. Parent gửi constraints xuống child ││ "Bạn có thể rộng 0-300, cao 0-200" │└───────────────────┬─────────────────────┘ ↓┌─────────────────────────────────────────┐│ 2. Child quyết định kích thước của nó ││ "Tôi sẽ rộng 150, cao 100" │└───────────────────┬─────────────────────┘ ↓┌─────────────────────────────────────────┐│ 3. Parent đặt vị trí cho child ││ "Bạn sẽ ở vị trí (75, 50)" │└─────────────────────────────────────────┘4. Tight vs Loose Constraints
Phần tiêu đề “4. Tight vs Loose Constraints”Tight Constraints
Phần tiêu đề “Tight Constraints”Min = Max, widget buộc phải có kích thước cụ thể:
BoxConstraints.tight(Size(100, 100))// minWidth = maxWidth = 100// minHeight = maxHeight = 100Loose Constraints
Phần tiêu đề “Loose Constraints”Min = 0, widget có thể chọn bất kỳ kích thước nào từ 0 đến max:
BoxConstraints.loose(Size(100, 100))// minWidth = 0, maxWidth = 100// minHeight = 0, maxHeight = 1005. Unbounded Constraints
Phần tiêu đề “5. Unbounded Constraints”Khi maxWidth/maxHeight là vô hạn:
// Trong ListView, height là unbounded// Trong Row, width là unbounded (cho children)⚠️ Đây là nguyên nhân gây ra nhiều lỗi layout!
6. Lỗi thường gặp
Phần tiêu đề “6. Lỗi thường gặp”“RenderBox was not laid out”
Phần tiêu đề ““RenderBox was not laid out””// ❌ Lỗi: Column trong Row, cả hai đều cố gắng expandRow( children: [ Column( children: [Text('Item 1'), Text('Item 2')], ), ],)
// ✅ Fix: Wrap với Expanded hoặc set kích thướcRow( children: [ Expanded( child: Column( children: [Text('Item 1'), Text('Item 2')], ), ), ],)“Vertical viewport was given unbounded height”
Phần tiêu đề ““Vertical viewport was given unbounded height””// ❌ Lỗi: ListView trong Column (cả hai expand vô hạn theo height)Column( children: [ ListView(...), ],)
// ✅ Fix 1: Wrap ListView với ExpandedColumn( children: [ Expanded( child: ListView(...), ), ],)
// ✅ Fix 2: Hoặc set shrinkWrapColumn( children: [ ListView( shrinkWrap: true, // ListView co theo nội dung ), ],)7. LayoutBuilder
Phần tiêu đề “7. LayoutBuilder”Đọc constraints trong runtime:
LayoutBuilder( builder: (context, constraints) { print('Max width: ${constraints.maxWidth}'); print('Max height: ${constraints.maxHeight}');
if (constraints.maxWidth > 600) { return WideLayout(); } else { return NarrowLayout(); } },)8. IntrinsicHeight / IntrinsicWidth
Phần tiêu đề “8. IntrinsicHeight / IntrinsicWidth”Cho children của Row/Column có cùng kích thước:
// Tất cả children trong Row có cùng heightIntrinsicHeight( child: Row( children: [ Container(color: Colors.red, width: 50, height: 100), Container(color: Colors.green, width: 50), // Sẽ có height = 100 Container(color: Colors.blue, width: 50), // Sẽ có height = 100 ], ),)⚠️ IntrinsicHeight/Width tốn performance, dùng hạn chế!
9. Một số widgets và constraints
Phần tiêu đề “9. Một số widgets và constraints”| Widget | Behavior |
|---|---|
Container |
Nếu không có child, expand full. Có child thì co theo child |
SizedBox |
Đặt constraints cụ thể |
ConstrainedBox |
Thêm constraints |
UnconstrainedBox |
Bỏ constraints (child có thể overflow) |
FractionallySizedBox |
Kích thước theo % của parent |
10. Debug Layout
Phần tiêu đề “10. Debug Layout”// Xem constraints trong debugWidget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { debugPrint('Constraints: $constraints'); return MyWidget(); }, );}Hoặc sử dụng Flutter DevTools → Layout Explorer.
📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| Khái niệm | Mô tả |
|---|---|
| Constraints | Giới hạn min/max của kích thước |
| Tight | min = max (kích thước cố định) |
| Loose | min = 0 (có thể nhỏ hơn) |
| Unbounded | max = infinity (nguy hiểm!) |
Quy tắc vàng:
- Constraints đi từ parent xuống child
- Sizes đi từ child lên parent
- Parent quyết định position của child