SnackBar & BottomSheet
Notifikasi ringan dan panel geser dari bawah.
Kenapa SnackBar & BottomSheet Ada?
Setelah user melakukan aksi, ia butuh tahu hasilnya. Tapi tidak semua hasil layak interupsi sebesar dialog. "Item tersimpan" tidak butuh tombol OK yang diklik, cukup pesan ringan yang hilang sendiri. SnackBar menyelesaikan masalah feedback ringan ini: muncul di bawah, tidak memblokir layar, dan bisa membawa satu aksi opsional seperti Urungkan.
BottomSheet menjawab kebutuhan yang berlawanan: user butuh memilih atau melakukan sesuatu yang butuh ruang lebih dari sebaris pesan, tapi belum layak pindah halaman penuh. Contoh klasik: pilih metode bayar, bagikan ke..., atau filter pencarian.
SnackBar Dasar
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Item ditambahkan ke keranjang'),
duration: Duration(seconds: 3),
),
);Selalu pakai ScaffoldMessenger, bukan Scaffold.of yang sudah deprecated. SnackBar butuh Scaffold sebagai ancestor dari context yang dipakai, kalau context-nya salah kamu akan dapat error "No ScaffoldMessenger found".
Contoh Nyata: Hapus dengan Urungkan
Pola paling berharga dari SnackBar adalah aksi destruktif yang bisa dibatalkan. Ini jauh lebih ramah daripada dialog konfirmasi untuk setiap penghapusan:
void _hapusItem(String item) {
setState(() => _daftar.remove(item));
ScaffoldMessenger.of(context)
..clearSnackBars()
..showSnackBar(
SnackBar(
content: Text('$item dihapus'),
duration: const Duration(seconds: 4),
action: SnackBarAction(
label: 'Urungkan',
onPressed: () => setState(() => _daftar.add(item)),
),
),
);
}clearSnackBars() memastikan snackbar lama langsung diganti yang baru, jadi menghapus tiga item cepat tidak membuat antrean pesan basi. Durasi 4 detik memberi cukup waktu membaca tanpa terlalu lama menutupi layar. Ini pola yang dipakai Gmail untuk "Pesan diarsipkan, Urungkan".
BottomSheet: Panel dari Bawah
Future<void> _pilihBayar() async {
final metode = await showModalBottomSheet<String>(
context: context,
builder: (context) => Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Pilih pembayaran',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
ListTile(
leading: const Icon(Icons.money),
title: const Text('Tunai'),
onTap: () => Navigator.pop(context, 'Tunai'),
),
ListTile(
leading: const Icon(Icons.qr_code),
title: const Text('QRIS'),
onTap: () => Navigator.pop(context, 'QRIS'),
),
],
),
),
);
if (metode != null && mounted) {
setState(() => _metodeBayar = metode);
}
}Sama seperti dialog, bottom sheet modal mengembalikan Future berisi nilai dari Navigator.pop. mainAxisSize: MainAxisSize.min membuat tingginya mengikuti konten, bukan memenuhi layar. Untuk bottom sheet yang berisi TextField, tambahkan isScrollControlled: true dan padding MediaQuery.of(context).viewInsets.bottom agar tidak tertutup keyboard.
Edge Case & Best Practice
Pertama, SnackBar yang dipanggil setelah await panjang wajib cek mounted dulu, karena halaman bisa sudah ditutup. Kedua, jangan menumpuk banyak snackbar untuk error validasi form, lebih baik tampilkan error inline di masing-masing field. Ketiga, aksi di SnackBar idealnya cuma satu dan singkat ("Urungkan", "Lihat"); kalau butuh dua tombol atau penjelasan panjang, itu tanda kamu butuh dialog atau bottom sheet.
Keempat, bottom sheet modal menutup saat tap di luar atau swipe ke bawah, jadi jangan taruh aksi destruktif tanpa konfirmasi di dalamnya. Kelima, ada juga versi persistent lewat Scaffold.of(context).showBottomSheet yang tidak memblokir layar belakang, cocok untuk mini player musik, tapi ia terikat pada Scaffold dan hilang saat pindah halaman.
Kapan TIDAK Memakai Ini
Untuk error kritis yang butuh keputusan ("Gagal menyimpan, coba lagi?"), pakai dialog, snackbar terlalu mudah terlewat. Untuk pesan sukses yang muncul tiap 5 detik, kurangi frekuensinya, feedback yang terlalu cerewet sama mengganggunya dengan tidak ada feedback. Untuk navigasi utama atau daftar panjang yang butuh scroll jauh, buat halaman tersendiri, bottom sheet yang kepanjangan susah dipakai. Dan jangan memakai bottom sheet hanya untuk menampilkan teks statis, itu tugas dialog atau halaman bantuan.
Catatan teknis:
ScaffoldMessengerjuga bisa menampilkanMaterialBanner, saudara SnackBar yang muncul di atas layar dan tidak hilang sendiri. Cocok untuk peringatan persisten seperti "Mode offline", lengkap dengan tombol aksi untuk menutupnya.
Tantangan
SnackBar undo
Saat item dihapus, tampilkan SnackBar 'Item dihapus' dengan action 'Urungkan' yang mengembalikan item ke daftar.
Kuis Bab
Uji pemahamanmu: Form & Input
Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".
1.Bagaimana membaca teks dari TextField?
2.Apa syarat validator di TextFormField?
3.Widget apa untuk pilihan ya/tidak dengan label?
4.Bagaimana membuat dialog konfirmasi yang mengembalikan pilihan user?
5.Bagaimana menampilkan SnackBar yang benar di Flutter modern?