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

↔️ Expanded & Flexible

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),
],
)

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%

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),
],
)

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


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,
),
),
],
)

Row(
children: [
Expanded(
child: TextField(
decoration: InputDecoration(hintText: 'Search...'),
),
),
SizedBox(width: 8),
ElevatedButton(onPressed: () {}, child: Text('Search')),
],
)
Row(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.grey[200],
child: ListView(...), // Sidebar
),
),
Expanded(
flex: 3,
child: Container(
child: Content(), // Main content
),
),
],
)
Row(
children: [
SizedBox(
width: 100,
child: Text('Username:'),
),
Expanded(
child: TextField(),
),
],
)

Column(
children: [
AppBar(title: Text('Title')), // Fixed height
Expanded(
child: ListView(...), // Chiếm phần còn lại
),
BottomNavigationBar(...), // Fixed height
],
)

// ❌ Lỗi: Expanded phải trong Row, Column, hoặc Flex
Container(
child: Expanded(
child: Text('Error'),
),
)
// ✅ Đúng
Row(
children: [
Expanded(child: Text('OK')),
],
)
// ❌ 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)),
],
),
)

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ệ