navigasibottombartabMenengah4 mnt baca

BottomNavigationBar

Navigasi tab bawah ala aplikasi modern dengan IndexedStack.

Kenapa Bottom Navigation?

Lihat aplikasi populer: Instagram, Tokopedia, Gojek. Navigasi utama selalu di bawah, dalam jangkauan jempol. BottomNavigationBar adalah widget bawaan Flutter untuk pola ini: deretan tab yang mengganti isi body, bukan menumpuk halaman baru. Bedanya dengan Navigator.push: pindah tab tidak menambah route ke stack, jadi tombol back tidak perlu melewati semua tab yang pernah dibuka. Ini membuat navigasi terasa ringan dan bisa diprediksi user.

Struktur Dasar

Pola standarnya memakai StatefulWidget yang menyimpan index tab aktif:

dart
class Beranda extends StatefulWidget {
  const Beranda({super.key});
  @override
  State<Beranda> createState() => _BerandaState();
}

class _BerandaState extends State<Beranda> {
  int _index = 0;

  final _halaman = const [
    HalamanMenu(),
    HalamanKeranjang(),
    HalamanProfil(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _halaman[_index],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _index,
        onTap: (i) => setState(() => _index = i),
        selectedItemColor: Colors.deepPurple,
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Beranda'),
          BottomNavigationBarItem(
            icon: Icon(Icons.shopping_cart),
            label: 'Keranjang',
          ),
          BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profil'),
        ],
      ),
    );
  }
}

Sederhana: _index menyimpan tab aktif, onTap mengubahnya lewat setState, dan body menampilkan halaman sesuai index. Tidak ada route yang di-push, tidak ada stack yang bertambah.

Jaga State dengan IndexedStack

Ada jebakan pada struktur di atas: body: _halaman[_index] membangun ulang halaman setiap pindah tab. Scroll di tab Menu yang sudah setengah jalan akan reset ke atas saat kamu mampir ke tab Profil lalu kembali. Form yang setengah diisi ikut hilang. Solusinya IndexedStack, yang membangun semua halaman sekali di awal dan hanya menampilkan satu:

dart
body: IndexedStack(
  index: _index,
  children: _halaman,
),

Perbedaannya terasa langsung: form checkout tiga langkah di satu tab tetap terisi walau user sempat mengecek tab lain. State seperti posisi scroll, teks input, dan pilihan filter semuanya terjaga karena widget tidak pernah di-dispose.

Catatan teknis: IndexedStack membangun semua children di awal, jadi jangan taruh halaman yang berat (misalnya yang langsung fetch API besar saat initState) di sana tanpa strategi lazy loading. Untuk kasus berat, pertimbangkan AutomaticKeepAlives atau pindahkan data ke state management.

Edge Cases & Best Practices

  • Empat tab atau lebih: set type: BottomNavigationBarType.fixed. Tanpa ini, label tab yang tidak aktif akan hilang karena default-nya adalah shifting.
  • Badge notifikasi: bungkus icon dengan Badge(label: Text('3'), child: Icon(Icons.shopping_cart)) untuk menampilkan angka di tab Keranjang.
  • Maksimal lima tab: ini batas desain Material. Lebih dari itu, pakai NavigationDrawer atau NavigationRail yang dirancang untuk banyak tujuan.
  • Warna dan label: selalu set selectedItemColor dan unselectedItemColor agar konsisten dengan tema aplikasi. Jangan biarkan label kosong kecuali desainnya memang icon-only.
  • Tab tengah menonjol: untuk tombol aksi utama (misalnya Kasir atau Tambah), pakai FloatingActionButton dengan floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked di atas BottomNavigationBar.

Kapan Jangan Pakai

BottomNavigationBar cocok untuk tiga sampai lima tujuan utama yang sederajat. Jangan pakai untuk alur bertingkat (Menu, Kategori, Produk, Detail): itu tugas Navigator.push di dalam tiap tab. Dan kalau tiap tab butuh riwayat navigasinya sendiri (tombol back di tab Profil tidak boleh keluar aplikasi), Navigator 1.0 tidak cukup: pakai StatefulShellRoute di go_router yang memberi setiap tab stack-nya sendiri.

Tantangan

3 tab + IndexedStack

Buat BottomNavigationBar 3 tab (Beranda, Cari, Profil) dengan IndexedStack agar state tiap tab terjaga saat berpindah.