Navigator

Berpindah layar dengan Navigator menggunakan push dan pop dengan route sebagai layar.

Daftar isi

Aplikasi nyata hampir selalu memiliki lebih dari satu layar, misalnya daftar catatan dan formulir tambah catatan. Topik ini membahas Navigator, widget bawaan Flutter yang mengelola perpindahan antarlayar melalui sebuah stack, beserta Navigator.push dan Navigator.pop sebagai pasangan perintahnya. Pada akhir topik, satu aplikasi catatan dua layar disusun utuh agar mekanisme tersebut dapat diamati dari kode yang lengkap.

Route dan stack pada Navigator#

Route adalah abstraksi satu layar pada Flutter, sedangkan Navigator adalah widget yang menyimpan route-route tersebut dalam stack. Stack bekerja dengan prinsip last in, first out, yakni elemen yang terakhir ditambahkan adalah elemen yang pertama diambil. Analogi yang tepat secara teknis adalah tumpukan piring, sebab piring baru hanya dapat diletakkan di bagian atas tumpukan dan piring yang diambil pun hanya piring teratas. Menaruh piring berpadanan dengan Navigator.push, sedangkan mengambil piring teratas berpadanan dengan Navigator.pop.

MaterialApp memasang Navigator secara otomatis pada aplikasi yang dibangun dengannya. Properti home menjadi route pertama yang menempati bagian bawah stack, sehingga layar yang tampil saat aplikasi dibuka adalah home itu sendiri. Keadaan stack yang hanya berisi satu route ini penting diingat karena memanggil Navigator.pop dalam keadaan tersebut akan mengosongkan stack.

Route yang berada di bawah route teratas tetap tersimpan dalam stack meskipun tidak terlihat. Kondisi ini menjaga isi layar sebelumnya, sehingga ketika pengguna kembali, pekerjaan yang sudah dibuat pada layar tersebut tidak hilang. Navigator juga menyediakan metode umum Navigator.of(context), sedangkan Navigator.push dan Navigator.pop merupakan bentuk singkat dari pemanggilan yang paling sering.

Diagram berikut menggambarkan tiga keadaan stack pada aplikasi catatan dengan layar Daftar catatan dan Tambah catatan, yaitu sebelum push, sesudah push, dan sesudah pop.

atasbawahSebelum pushDaftar catatanstack berisi satu routepushSesudah pushTambah catatanDaftar catatanroute baru ditumpuk di ataspopSesudah popDaftar catatanlayar teratas dihapus
Tiga keadaan stack Navigator: sebelum push, sesudah push, dan sesudah pop

Push tidak menggantikan route lama, melainkan menumpuk route baru di atasnya, sedangkan pop selalu menghapus route teratas. Karena itu, kembali dari Tambah catatan ke Daftar catatan tidak memerlukan pembukaan ulang layar dan cukup dilakukan dengan Navigator.pop. Diagram tersebut juga menunjukkan bahwa route Daftar catatan tidak pernah keluar dari stack, sehingga keadaannya tetap terjaga selama Tambah catatan terbuka.

Berpindah dengan push dan pop#

Navigator.push menerima dua argumen, yaitu BuildContext yang sedang aktif dan objek Route yang akan ditumpuk. Route layar penuh yang paling sering digunakan adalah MaterialPageRoute, turunan PageRoute yang menyediakan transisi khas platform. Layar tujuan disusun melalui builder, yaitu fungsi yang menerima context milik route baru dan mengembalikan widget layar tujuan.

dart Contoh: mendorong layar tambah catatan ke stack
// tidak-dijalankan
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => const LayarTambahCatatan()),
);

Navigator.pop menghapus route teratas, dan context yang diberikan menentukan Navigator yang dimaksud. Pada Scaffold dengan AppBar, tombol kembali tampil otomatis ketika route dapat di-pop, dan tombol tersebut memanggil Navigator.pop tanpa kode tambahan. Perintah eksplisit tetap diperlukan ketika kembali dipicu oleh tombol lain di dalam layar.

dart Contoh: menghapus layar teratas dengan pop
// tidak-dijalankan
Navigator.pop(context);

Argumen context pada kedua metode bukan formalitas. Navigator dicari dari context tersebut dengan menelusuri pohon widget ke atas, sehingga context yang digunakan harus berada di bawah MaterialApp. Context milik widget yang sudah dilepas dari pohon, misalnya layar yang sedang ditutup, tidak lagi memiliki jalur ke Navigator, sehingga pemanggilan dengan context tersebut memunculkan error.

Aplikasi catatan dua layar#

Contoh utuh berikut menyusun dua layar dalam satu berkas main.dart. Layar LayarDaftarCatatan menjadi home dan berisi tombol tambah yang memanggil Navigator.push, sedangkan layar LayarTambahCatatan berisi tombol yang memanggil Navigator.pop. Salin berkas ini ke proyek Flutter, lalu jalankan pada emulator untuk mengamati perpindahannya.

dart main.dart
// tidak-dijalankan
import 'package:flutter/material.dart';

void main() {
  runApp(const AplikasiCatatan());
}

class AplikasiCatatan extends StatelessWidget {
  const AplikasiCatatan({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Catatan',
      theme: ThemeData(colorSchemeSeed: Colors.teal),
      home: const LayarDaftarCatatan(),
    );
  }
}

class LayarDaftarCatatan extends StatelessWidget {
  const LayarDaftarCatatan({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Daftar catatan')),
      body: const Center(child: Text('Belum ada catatan.')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => const LayarTambahCatatan(),
            ),
          );
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

class LayarTambahCatatan extends StatelessWidget {
  const LayarTambahCatatan({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Tambah catatan')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Kembali ke daftar'),
        ),
      ),
    );
  }
}

Bagian yang patut dicermati adalah onPressed pada FloatingActionButton, yang mewakili pola paling umum, yaitu perpindahan dipicu dari dalam callback. Route yang didorong dibuat baru setiap kali Navigator.push dipanggil, sehingga keadaan LayarTambahCatatan dari kunjungan sebelumnya tidak dibawa kembali. Perilaku ini cocok untuk layar formulir yang selalu dimulai kosong, tetapi perlu ditinjau ulang untuk layar yang seharusnya mengingat keadaannya.

Kesalahan umum#

Memanggil Navigator.pop pada layar pertama adalah kesalahan yang sering terjadi. Stack menjadi kosong dan tidak ada route untuk dirender, sehingga tampilan aplikasi menjadi hitam. Perbaikannya berupa disiplin sederhana, yaitu pop hanya dipanggil dari layar yang sebelumnya dibuka melalui push, sedangkan penutupan layar terakhir diserahkan ke sistem.

Kesalahan lain adalah mendorong route yang sama berkali-kali karena tombol yang sama ditekan beberapa kali dalam waktu singkat. Stack kemudian memuat beberapa salinan layar identik, sehingga tombol kembali harus ditekan sebanyak jumlah salinan tersebut agar aplikasi benar-benar kembali ke layar semula. Pencegahannya berupa menonaktifkan tombol selama transisi berlangsung atau memeriksa keadaan stack sebelum mendorong route baru.

Ringkasan#

  • Navigator mengelola layar sebagai stack route dengan prinsip last in, first out, dan MaterialApp memasangnya secara otomatis.
  • Navigator.push menumpuk route baru di atas stack, sedangkan Navigator.pop menghapus route teratas dan menampilkan kembali layar di bawahnya.
  • MaterialPageRoute menyediakan route layar penuh dengan transisi khas platform dan menyusun layar tujuan melalui builder.

Referensi#