Expanded và Flexible trong Flutter
1. Expanded Widget
Expanded chiếm toàn bộ không gian còn lại trong Row/Column:
Row(
children: [
Container(width: 50, height: 50, color: Colors.red),
Expanded(
child: Container(height: 50, color: Colors.green), // Chiếm hết phần còn lại
),
Container(width: 50, height: 50, color: Colors.blue),
],
)2. Flex Factor
Khi có nhiều Expanded, dùng flex để phân chia tỷ lệ:
Row(
children: [
Expanded(
flex: 1,
child: Container(height: 50, color: Colors.red),
),
Expanded(
flex: 2, // Gấp đôi phần đỏ
child: Container(height: 50, color: Colors.green),
),
Expanded(
flex: 1,
child: Container(height: 50, color: Colors.blue),
),
],
)
// Kết quả: Red = 25%, Green = 50%, Blue = 25%3. Flexible Widget
Flexible có thể chiếm không gian, nhưng không bắt buộc phải fill hết:
Row(
children: [
Flexible(
child: Container(
width: 100, // Có thể nhỏ hơn available space
height: 50,
color: Colors.red,
),
),
Container(width: 100, height: 50, color: Colors.blue),
],
)4. FlexFit
Flexible có property fit:
Flexible(
fit: FlexFit.loose, // Mặc định - có thể nhỏ hơn
child: Container(...),
)
Flexible(
fit: FlexFit.tight, // Buộc fill hết = Expanded
child: Container(...),
)| Fit | Mô tả |
|---|---|
FlexFit.loose | Child có thể nhỏ hơn available space |
FlexFit.tight | Child phải fill hết available space |
Expanded = Flexible với fit: FlexFit.tight
5. So sánh Expanded vs Flexible
Row(
children: [
// Expanded: PHẢI fill hết
Expanded(
child: Container(height: 50, color: Colors.red),
),
// Flexible (loose): CÓ THỂ nhỏ hơn
Flexible(
child: Container(
width: 50, // Chỉ cần 50, không cần fill
height: 50,
color: Colors.blue,
),
),
],
)6. Ví dụ thực tế
Search Bar
Row(
children: [
Expanded(
child: TextField(
decoration: InputDecoration(hintText: 'Search...'),
),
),
SizedBox(width: 8),
ElevatedButton(onPressed: () {}, child: Text('Search')),
],
)Two-column Layout
Row(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.grey[200],
child: ListView(...), // Sidebar
),
),
Expanded(
flex: 3,
child: Container(
child: Content(), // Main content
),
),
],
)Form với Labels
Row(
children: [
SizedBox(
width: 100,
child: Text('Username:'),
),
Expanded(
child: TextField(),
),
],
)7. Expanded trong Column
Column(
children: [
AppBar(title: Text('Title')), // Fixed height
Expanded(
child: ListView(...), // Chiếm phần còn lại
),
BottomNavigationBar(...), // Fixed height
],
)8. Lỗi thường gặp
Expanded ngoài Row/Column
// ❌ Lỗi: Expanded phải trong Row, Column, hoặc Flex
Container(
child: Expanded(
child: Text('Error'),
),
)
// ✅ Đúng
Row(
children: [
Expanded(child: Text('OK')),
],
)Nhiều Expanded không có kích thước
// ❌ Có thể gây lỗi nếu không có bounded constraints
Column(
children: [
Expanded(child: Container()),
Expanded(child: Container()),
],
)
// ✅ Đảm bảo Column có bounded height
SizedBox(
height: 400,
child: Column(
children: [
Expanded(child: Container(color: Colors.red)),
Expanded(child: Container(color: Colors.blue)),
],
),
)📝 Tóm tắt
| Widget | Behavior | Khi nào dùng |
|---|---|---|
Expanded | Buộc fill hết không gian | Muốn stretch child |
Flexible(loose) | Có thể nhỏ hơn | Child có kích thước riêng |
Flexible(tight) | = Expanded | Hiếm khi dùng trực tiếp |
Flex factor:
- flex: 1 → 1 phần
- flex: 2 → 2 phần
- Tổng = tổng các flex, chia theo tỷ lệ
Last updated on