↔️ Expanded & Flexible
1. Expanded Widget
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “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ế
Phần tiêu đề “6. Ví dụ thực tế”Search Bar
Phần tiêu đề “Search Bar”Row( children: [ Expanded( child: TextField( decoration: InputDecoration(hintText: 'Search...'), ), ), SizedBox(width: 8), ElevatedButton(onPressed: () {}, child: Text('Search')), ],)Two-column Layout
Phần tiêu đề “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
Phần tiêu đề “Form với Labels”Row( children: [ SizedBox( width: 100, child: Text('Username:'), ), Expanded( child: TextField(), ), ],)7. Expanded trong Column
Phần tiêu đề “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
Phần tiêu đề “8. Lỗi thường gặp”Expanded ngoài Row/Column
Phần tiêu đề “Expanded ngoài Row/Column”// ❌ Lỗi: Expanded phải trong Row, Column, hoặc FlexContainer( child: Expanded( child: Text('Error'), ),)
// ✅ ĐúngRow( children: [ Expanded(child: Text('OK')), ],)Nhiều Expanded không có kích thước
Phần tiêu đề “Nhiều Expanded không có kích thước”// ❌ Có thể gây lỗi nếu không có bounded constraintsColumn( children: [ Expanded(child: Container()), Expanded(child: Container()), ],)
// ✅ Đảm bảo Column có bounded heightSizedBox( height: 400, child: Column( children: [ Expanded(child: Container(color: Colors.red)), Expanded(child: Container(color: Colors.blue)), ], ),)📝 Tóm tắt
Phần tiêu đề “📝 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ệ