🔲 GridView
1. GridView.count
Phần tiêu đề “1. GridView.count”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), ],)2. GridView.builder
Phần tiêu đề “2. GridView.builder”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')), ); },)3. GridView.extent
Phần tiêu đề “3. GridView.extent”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), ],)4. SliverGridDelegate
Phần tiêu đề “4. SliverGridDelegate”FixedCrossAxisCount
Phần tiêu đề “FixedCrossAxisCount”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),)MaxCrossAxisExtent
Phần tiêu đề “MaxCrossAxisExtent”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),)5. Padding và Spacing
Phần tiêu đề “5. Padding và Spacing”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: [...],)6. Aspect Ratio
Phần tiêu đề “6. Aspect Ratio”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 |
7. shrinkWrap
Phần tiêu đề “7. shrinkWrap”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'), ],)8. Ví dụ thực tế
Phần tiêu đề “8. Ví dụ thực tế”Photo Gallery
Phần tiêu đề “Photo Gallery”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, ), ); },)Product Grid
Phần tiêu đề “Product Grid”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}'), ], ), ), ], ), ); },)Icon Grid
Phần tiêu đề “Icon Grid”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)), ], );}9. Responsive Grid
Phần tiêu đề “9. Responsive Grid”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]), ); },)📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| 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 |