GridView: Tata Letak Berbasis Grid
Susun item dalam grid rapi dengan GridView, atur jumlah kolom dan rasio aspek tiap sel.
Kapan pakai grid?
Grid cocok untuk katalog produk, galeri foto, atau menu kategori, situasi di mana item-item punya ukuran seragam dan disusun berbaris ke samping. Kalau item tingginya beda-beda jauh, pertimbangkan staggered grid dari package, karena GridView bawaan memaksa sel yang seragam.
GridView.count: cara tercepat
GridView.count(
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
padding: const EdgeInsets.all(12),
childAspectRatio: 3 / 4,
children: List.generate(10, (index) {
return Container(
decoration: BoxDecoration(
color: Colors.teal.shade100,
borderRadius: BorderRadius.circular(12),
),
child: Center(child: Text('Item $index')),
);
}),
)crossAxisCount menentukan jumlah kolom. childAspectRatio adalah rasio lebar banding tinggi tiap sel, jadi 3 / 4 berarti sel lebih tinggi daripada lebar, cocok untuk kartu produk portrait.
GridView.builder: untuk data dinamis
Sama seperti ListView, versi builder me-render sel secara lazy dan wajib untuk data dari API:
GridView.builder(
padding: const EdgeInsets.all(12),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 0.75,
),
itemCount: produk.length,
itemBuilder: (context, index) => KartuProduk(produk: produk[index]),
)SliverGridDelegateWithFixedCrossAxisCount mengatur jumlah kolom tetap. Alternatifnya SliverGridDelegateWithMaxCrossAxisExtent yang menentukan lebar maksimal tiap sel, sehingga jumlah kolom otomatis menyesuaikan lebar layar. Yang kedua lebih cocok untuk layout responsif.
Kartu produk realistis
Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Image.network(
produk.gambarUrl,
fit: BoxFit.cover,
errorBuilder: (c, e, s) => const Icon(Icons.broken_image),
),
),
Padding(
padding: const EdgeInsets.all(8),
child: Text(produk.nama, maxLines: 1, overflow: TextOverflow.ellipsis),
),
Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
child: Text(
'Rp${produk.harga}',
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
],
),
)Card memberi bayangan dan sudut membulat khas Material. clipBehavior: Clip.antiAlias memastikan gambar terpotong rapi mengikuti sudut kartu.
Catatan teknis: GridView di dalam
Columnatau di dalam scroll view lain memicu error viewport yang sama seperti ListView. Solusinya identik: bungkus denganExpanded, atau setshrinkWrap: trueplusphysics: NeverScrollableScrollPhysics()kalau grid memang bagian dari halaman scroll yang lebih besar. Jangan lupa,childAspectRatioyang salah adalah penyebab umum sel terlihat gepeng atau terlalu tinggi, hitung dari desain yang kamu mau.