Layout Responsif: Adaptif Berbagai Ukuran Layar
Buat UI yang rapi di HP kecil, HP besar, dan tablet dengan MediaQuery, LayoutBuilder, dan breakpoint.
Masalah fragmentasi layar
Android punya ribuan ukuran layar. Layout yang pas di HP-mu bisa overflow di HP kecil atau terlihat kosong melompong di tablet. Desain responsif berarti layout menyesuaikan ruang yang tersedia, bukan mengasumsikan satu ukuran.
MediaQuery: baca ukuran layar
@override
Widget build(BuildContext context) {
final lebar = MediaQuery.of(context).size.width;
final jumlahKolom = lebar < 600 ? 2 : lebar < 900 ? 3 : 4;
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: jumlahKolom,
),
itemCount: produk.length,
itemBuilder: (context, i) => KartuProduk(produk: produk[i]),
);
}Pola breakpoint sederhana: di bawah 600 (HP) 2 kolom, 600-900 (HP besar/foldable) 3 kolom, di atas 900 (tablet) 4 kolom.
LayoutBuilder: responsif per widget
MediaQuery membaca ukuran layar penuh. LayoutBuilder membaca ukuran yang tersedia untuk widget itu sendiri, lebih tepat untuk komponen reusable:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 400) {
// Layar sempit: susun vertikal
return Column(
children: [GambarProduk(), InfoProduk()],
);
}
// Layar lega: susun horizontal
return Row(
children: [GambarProduk(), Expanded(child: InfoProduk())],
);
},
)Komponen ini otomatis menyesuaikan diri entah ditaruh di HP, di setengah layar tablet, atau di dialog.
OrientationBuilder
Untuk perbedaan portrait vs landscape yang drastis:
OrientationBuilder(
builder: (context, orientation) {
final isLandscape = orientation == Orientation.landscape;
return GridView.count(
crossAxisCount: isLandscape ? 4 : 2,
children: [...],
);
},
)Hindari nilai piksel kaku
Ganti ukuran fixed dengan proporsi atau Expanded/Flexible. Daripada Container(width: 350), pakai FractionallySizedBox atau biarkan parent yang menentukan. Teks pakai FittedBox atau atur maxLines agar tidak overflow di layar kecil.
// Buruk: kaku di semua layar
Container(width: 350, child: ...)
// Baik: mengikuti parent
SizedBox(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ...,
),
)Catatan teknis: Memanggil
MediaQuery.of(context)di widget yang rebuild karena animasi akan ikut rebuild setiap ada perubahan metrics, tapi itu jarang masalah. Yang lebih penting: test di minimal tiga ukuran (kecil 360px, standar 412px, tablet 800px) memakai device preview atau emulator berbeda. Bug responsif hampir tidak pernah ketahuan kalau cuma test di satu emulator.