Stack dan Positioned: Menumpuk Widget
Tumpuk widget saling di atas dengan Stack dan atur posisi presisi dengan Positioned.
Konsep menumpuk
Row dan Column menyusun widget bersebelahan. Stack menyusunnya bertumpuk: anak pertama di paling bawah, anak berikutnya di atasnya. Cocok untuk badge di atas ikon, teks di atas gambar, atau tombol mengambang di atas peta.
Stack(
children: [
Image.asset('assets/images/produk.png', width: 200, height: 200, fit: BoxFit.cover),
Positioned(
top: 8,
right: 8,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(12),
),
child: const Text(
'Diskon 20%',
style: TextStyle(color: Colors.white, fontSize: 12),
),
),
),
],
)Label diskon menempel di pojok kanan atas gambar produk, pola yang sangat umum di aplikasi katalog.
Positioned dan posisinya
Positioned mengatur jarak anak dari tepi Stack lewat top, bottom, left, right, plus width dan height opsional. Beberapa pola umum:
const Stack(
children: [
SizedBox(height: 200),
// Menempel di bawah, selebar Stack
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Text('Keterangan di bawah', textAlign: TextAlign.center),
),
],
)Positioned.fill adalah jalan pintas untuk menutupi seluruh area Stack, sering dipakai untuk overlay loading seperti Positioned.fill(child: Center(child: CircularProgressIndicator())).
Anak tanpa Positioned
Anak Stack yang tidak dibungkus Positioned akan diposisikan sesuai alignment milik Stack (default topStart, pojok kiri atas). Kamu bisa mengubahnya misalnya menjadi Alignment.center agar semua anak non-positioned terpusat.
Kapan tidak pakai Stack?
Stack itu powerful tapi mudah disalahgunakan. Untuk layout form atau daftar biasa, Row dan Column lebih mudah dibaca dan lebih aman dari overflow. Pakai Stack hanya saat benar-benar butuh tumpukan visual: overlay, badge, watermark, atau efek parallax sederhana.
Catatan teknis: Stack tidak mencegah anaknya overflow keluar batas. Widget yang diposisikan di luar area Stack akan terpotong (clip) mengikuti
clipBehavior(defaultClip.hardEdge). Kalau badge-mu terpotong setengah, cek apakah Positioned-nya keluar dari area Stack, atau setclipBehavior: Clip.nonekalau memang disengaja. Hati-hati, Clip.none bisa membuat widget menimpa area di luar yang tidak diinginkan.