navigasinavigatorrouteMenengah4 mnt baca

Navigator.push

Pindah halaman dengan MaterialPageRoute dan tumpukan navigasi.

Analogi: Tumpukan Piring

Bayangkan tumpukan piring di dapur. Menaruh piring baru di atas tumpukan itu push: piring lama tetap ada di bawah, tertutup sementara. Mengambil piring teratas itu pop: piring di bawahnya muncul lagi persis seperti semula, lengkap dengan "isi"-nya (state yang tidak hilang).

Navigasi Flutter bekerja persis seperti itu. Setiap halaman adalah piring, dan Navigator mengelola tumpukannya (disebut route stack). Tombol back di Android pada dasarnya memanggil pop: mengambil halaman teratas sehingga halaman sebelumnya muncul kembali.

Contoh 1: Push Dasar dan Mengirim Data

Pola paling umum: dari daftar, ketuk item untuk membuka halaman detail, sambil mengirim objek data lewat constructor.

dart
// Di halaman daftar
ListTile(
  title: Text(produk.nama),
  trailing: const Icon(Icons.chevron_right),
  onTap: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => HalamanDetail(produk: produk),
      ),
    );
  },
);

// Halaman tujuan menerima data lewat constructor biasa
class HalamanDetail extends StatelessWidget {
  final Produk produk;

  const HalamanDetail({super.key, required this.produk});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(produk.nama)),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text('Harga: ${formatRupiah(produk.harga)}'),
      ),
    );
  }
}

MaterialPageRoute memberi animasi transisi bawaan sesuai platform (geser dari kanan di Android, dari bawah di iOS untuk fullscreen dialog). Parameter builder dipanggil Flutter untuk membangun halaman tujuan.

Contoh 2: Menunggu Hasil dengan Pop Berdata

Navigasi tidak cuma satu arah. Halaman yang dibuka bisa mengembalikan data saat ditutup, seperti formulir pemilih warna atau tanggal.

dart
// Membuka halaman pilih warna, lalu menunggu hasilnya
Future<void> _pilihWarna() async {
  final dipilih = await Navigator.push<String>(
    context,
    MaterialPageRoute(builder: (context) => const HalamanPilihWarna()),
  );
  // Widget ini mungkin sudah tidak ada saat future selesai!
  if (!mounted) return;
  if (dipilih != null) {
    setState(() => warna = dipilih);
  }
}

// Di halaman pilih warna: kembalikan data lewat pop
ListTile(
  title: const Text('Merah'),
  onTap: () => Navigator.pop(context, 'merah'),
)

Dua detail penting di sini: Navigator.push<String> menentukan tipe data yang dikembalikan, dan pengecekan mounted setelah await memastikan widget pemanggil masih hidup sebelum setState dipanggil. Tanpa cek ini, kamu bisa kena error "setState called after dispose".

Edge Cases

  • Context yang tidak valid: jangan simpan context di field atau variabel global lalu dipakai nanti. Selalu pakai context yang datang dari parameter build atau dari callback yang sedang berjalan.
  • Back bawaan vs data belum tersimpan: tombol back otomatis mem-pop tanpa bertanya. Kalau halaman berisi formulir yang belum disimpan, bungkus dengan PopScope (Flutter 3.10+) untuk menampilkan dialog konfirmasi "Yakin ingin keluar?".
  • Push berkali-kali: menekan tombol "detail" cepat berkali-kali bisa mendorong halaman yang sama berkali-kali ke stack. Nonaktifkan tombol saat proses push, atau cek sebelum push.

Kapan JANGAN Memakai Push Mentah

  • Alur login dan onboarding: setelah login berhasil, pakai pushReplacement atau pushAndRemoveUntil agar pengguna tidak bisa menekan back dan kembali ke halaman login.
  • Deep link dan URL web: push mentah tidak punya nama route, jadi tidak bisa diakses lewat URL. Pakai named routes (Navigator.pushNamed) atau go_router (Navigator 2.0) kalau butuh deep linking.
  • Stack yang dalam dan kompleks (tab + dialog + halaman bersarang): pertimbangkan go_router agar seluruh struktur navigasi terdefinisi di satu tempat.

Praktik Terbaik

  • Untuk transisi custom (fade, scale, shared element), pakai PageRouteBuilder alih-alih mengakali MaterialPageRoute.
  • Saat jumlah halaman melewati 5, pindahkan ke named routes agar daftar route terpusat dan mudah di-refactor.
  • Jangan pernah memanggil Navigator.push di dalam build secara langsung: dorong navigasi dari event (ketukan tombol) atau dari addPostFrameCallback, bukan dari proses membangun UI.

Catatan teknis: Navigator yang kamu pakai sebenarnya adalah Navigator 1.0 (imperative API). Ia tetap didukung penuh dan cocok untuk sebagian besar aplikasi; Navigator 2.0 (declarative, via go_router) baru dibutuhkan saat kamu berurusan dengan URL, deep link, atau web.

Tantangan

Dua halaman

Buat HalamanA dengan tombol 'Ke Halaman B'. HalamanB menampilkan teks 'Ini Halaman B' dan AppBar otomatis punya tombol back.