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

🔲 GridView

Grid với số cột cố định:

GridView.count(
crossAxisCount: 2, // 2 cột
children: [
Container(color: Colors.red),
Container(color: Colors.green),
Container(color: Colors.blue),
Container(color: Colors.yellow),
],
)

Lazy loading cho danh sách lớn:

GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemCount: 100,
itemBuilder: (context, index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(child: Text('$index')),
);
},
)

Grid với chiều rộng tối đa cho mỗi item:

GridView.extent(
maxCrossAxisExtent: 150, // Mỗi item tối đa 150px rộng
children: [
Container(color: Colors.red),
Container(color: Colors.green),
Container(color: Colors.blue),
],
)

Số cột cố định:

GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10, // Spacing dọc
crossAxisSpacing: 10, // Spacing ngang
childAspectRatio: 1.5, // Tỷ lệ width/height
),
itemCount: 20,
itemBuilder: (context, index) => Container(color: Colors.blue),
)

Chiều rộng tối đa, số cột tự động:

GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 1.0,
),
itemCount: 20,
itemBuilder: (context, index) => Container(color: Colors.green),
)

GridView.count(
crossAxisCount: 2,
padding: EdgeInsets.all(16), // Padding cho grid
mainAxisSpacing: 10, // Spacing dọc giữa items
crossAxisSpacing: 10, // Spacing ngang giữa items
children: [...],
)

Tỷ lệ chiều rộng / chiều cao của item:

GridView.count(
crossAxisCount: 2,
childAspectRatio: 16 / 9, // Wide items
children: [...],
)
Ratio Kết quả
1.0 Hình vuông
2.0 Rộng gấp đôi cao
0.5 Cao gấp đôi rộng
16/9 Video ratio

Giống ListView, co grid theo nội dung:

Column(
children: [
Text('Header'),
GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
Container(color: Colors.red, height: 50),
Container(color: Colors.blue, height: 50),
],
),
Text('Footer'),
],
)

GridView.builder(
padding: EdgeInsets.all(8),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
),
itemCount: photos.length,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.network(
photos[index],
fit: BoxFit.cover,
),
);
},
)
GridView.builder(
padding: EdgeInsets.all(16),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: 0.7, // Cao hơn rộng
),
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Image.network(product.image, fit: BoxFit.cover),
),
Padding(
padding: EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(product.name, style: TextStyle(fontWeight: FontWeight.bold)),
Text('\$${product.price}'),
],
),
),
],
),
);
},
)
GridView.count(
crossAxisCount: 4,
padding: EdgeInsets.all(16),
mainAxisSpacing: 16,
crossAxisSpacing: 16,
children: [
_buildIconItem(Icons.home, 'Home'),
_buildIconItem(Icons.search, 'Search'),
_buildIconItem(Icons.favorite, 'Favorite'),
_buildIconItem(Icons.settings, 'Settings'),
_buildIconItem(Icons.person, 'Profile'),
_buildIconItem(Icons.notifications, 'Alerts'),
_buildIconItem(Icons.mail, 'Mail'),
_buildIconItem(Icons.camera, 'Camera'),
],
)
Widget _buildIconItem(IconData icon, String label) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 32),
SizedBox(height: 4),
Text(label, style: TextStyle(fontSize: 12)),
],
);
}

LayoutBuilder(
builder: (context, constraints) {
int crossAxisCount = 2;
if (constraints.maxWidth > 600) crossAxisCount = 3;
if (constraints.maxWidth > 900) crossAxisCount = 4;
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
),
itemCount: items.length,
itemBuilder: (context, index) => ItemCard(items[index]),
);
},
)

Constructor Khi nào dùng
GridView.count() Số cột cố định, ít items
GridView.extent() Chiều rộng item cố định
GridView.builder() Nhiều items, lazy loading
Property Mô tả
crossAxisCount Số cột
maxCrossAxisExtent Chiều rộng tối đa
mainAxisSpacing Spacing dọc
crossAxisSpacing Spacing ngang
childAspectRatio Tỷ lệ w/h