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

🎁 Wrap Widget

Wrap tự động xuống dòng khi children vượt quá không gian:

Wrap(
children: [
Chip(label: Text('Tag 1')),
Chip(label: Text('Tag 2')),
Chip(label: Text('Tag 3')),
Chip(label: Text('Tag 4')),
Chip(label: Text('Tag 5')),
],
)

// ❌ Row: Overflow khi không đủ chỗ
Row(
children: [Chip(label: Text('Long tag 1')), Chip(label: Text('Long tag 2')), ...],
)
// ✅ Wrap: Tự động xuống dòng
Wrap(
children: [Chip(label: Text('Long tag 1')), Chip(label: Text('Long tag 2')), ...],
)

Wrap(
spacing: 8, // Khoảng cách ngang giữa children
runSpacing: 8, // Khoảng cách giữa các dòng
children: [
Chip(label: Text('Tag 1')),
Chip(label: Text('Tag 2')),
Chip(label: Text('Tag 3')),
],
)

Wrap(
alignment: WrapAlignment.center, // Căn giữa các items trên mỗi dòng
children: [...],
)
Giá trị Mô tả
start Đầu dòng (mặc định)
end Cuối dòng
center Giữa dòng
spaceBetween Khoảng cách đều, không có ở đầu/cuối
spaceAround Khoảng cách đều, nửa ở đầu/cuối
spaceEvenly Khoảng cách đều hoàn toàn
Wrap(
runAlignment: WrapAlignment.center, // Căn các dòng theo chiều dọc
children: [...],
)
Wrap(
crossAxisAlignment: WrapCrossAlignment.center, // Căn children theo cross axis
children: [...],
)

Wrap(
direction: Axis.vertical, // Wrap theo chiều dọc
children: [...],
)

Wrap(
spacing: 8,
runSpacing: 8,
children: [
Chip(
label: Text('Flutter'),
onDeleted: () {},
),
Chip(
label: Text('Dart'),
onDeleted: () {},
),
Chip(
label: Text('Mobile'),
onDeleted: () {},
),
Chip(
label: Text('Cross-platform'),
onDeleted: () {},
),
],
)
Wrap(
spacing: 8,
runSpacing: 8,
children: [
FilterChip(
label: Text('All'),
selected: true,
onSelected: (v) {},
),
FilterChip(
label: Text('Active'),
selected: false,
onSelected: (v) {},
),
FilterChip(
label: Text('Completed'),
selected: false,
onSelected: (v) {},
),
],
)
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
onPressed: () {},
icon: Icon(Icons.share),
label: Text('Share'),
),
ElevatedButton.icon(
onPressed: () {},
icon: Icon(Icons.download),
label: Text('Download'),
),
ElevatedButton.icon(
onPressed: () {},
icon: Icon(Icons.print),
label: Text('Print'),
),
],
)
Wrap(
spacing: 8,
runSpacing: 8,
children: skills.map((skill) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.blue.shade100,
borderRadius: BorderRadius.circular(20),
),
child: Text(skill),
);
}).toList(),
)
Wrap(
spacing: 4,
runSpacing: 4,
children: images.map((url) {
return ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.network(
url,
width: 80,
height: 80,
fit: BoxFit.cover,
),
);
}).toList(),
)

Flow cho phép vị trí tùy chỉnh hoàn toàn nhưng phức tạp hơn:

// Wrap: Đơn giản, auto wrap
Wrap(children: [...])
// Flow: Custom positioning, cần FlowDelegate
Flow(
delegate: MyFlowDelegate(),
children: [...],
)

💡 Dùng Wrap cho hầu hết trường hợp, Flow chỉ khi cần layout đặc biệt.


Property Mô tả
spacing Khoảng cách ngang
runSpacing Khoảng cách giữa các dòng
alignment Căn chỉnh trên mỗi dòng
runAlignment Căn chỉnh các dòng
crossAxisAlignment Căn chỉnh theo cross axis
direction Horizontal hoặc Vertical

Use cases phổ biến:

  • Tags / Chips
  • Filter buttons
  • Skills / Badges
  • Action buttons
  • Thumbnail galleries