Route bernama

Mendefinisikan tabel route bernama dan meneruskan argumennya.

Daftar isi

Mendorong kelas layar langsung melalui MaterialPageRoute cukup memadai selama jumlah perpindahan masih sedikit. Route bernama menawarkan cara kedua, yaitu setiap layar didaftarkan pada sebuah tabel dengan nama berbentuk string, lalu perpindahan dilakukan dengan menyebut nama route tersebut. Topik ini membahas pembentukan tabel routes pada MaterialApp, perpindahan dengan pushNamed dan popAndPushNamed, penerusan argumen, penanganan route dinamis melalui onGenerateRoute, serta kapan route bernama layak dipilih.

Tabel routes pada MaterialApp#

Route bernama adalah route yang diidentifikasi oleh sebuah string, misalnya ‘/tambah’, alih-alih oleh kelas layarnya. Tabel routes pada MaterialApp bertipe Map<String, WidgetBuilder>, yaitu pemetaan nama route ke fungsi builder yang mengembalikan widget layar. Berdasarkan konvensi, kunci ‘/’ menunjuk layar awal, sedangkan kunci lainnya ditulis dengan awalan garis miring.

dart Contoh: tabel routes dengan dua layar
// tidak-dijalankan
return MaterialApp(
  title: 'Catatan',
  initialRoute: '/',
  routes: {
    '/': (context) => const LayarDaftarCatatan(),
    '/tambah': (context) => const LayarTambahCatatan(),
  },
);

Ketika tabel routes sudah memuat kunci ‘/’, properti home tidak perlu dideklarasikan lagi karena kunci tersebut berperan sebagai layar awal. Perpindahan berikutnya tidak lagi memerlukan penyusunan MaterialPageRoute secara manual dan cukup menyebut nama route melalui Navigator.pushNamed. Apabila nama yang diminta tidak terdaftar dan tidak ada penanganan tambahan, Flutter memunculkan error saat aplikasi berjalan.

dart Contoh: membuka layar lewat nama route
// tidak-dijalankan
Navigator.pushNamed(context, '/tambah');

Pemanggilan tersebut membuka layar tambah catatan tanpa menyusun route di tempat pemanggilan. Seluruh daftar layar yang dimiliki aplikasi kini terkumpul pada satu tabel, dan nama route dapat dipanggil dari tombol mana pun.

Nilai pada tabel berupa WidgetBuilder, sehingga widget layar tidak dibangun saat aplikasi dimulai. Pemanggilan fungsi builder baru terjadi ketika route dengan nama tersebut didorong ke stack. Dengan begitu, mendeklarasikan puluhan route dalam satu tabel tidak berarti membangun puluhan layar sekaligus.

Mengganti layar dengan popAndPushNamed#

Tidak semua perpindahan menumpuk layar baru di atas yang lama. Setelah catatan tersimpan, layar formulir seharusnya hilang dari stack sehingga tombol kembali tidak membawa pengguna ke formulir yang sudah selesai diisi. Navigator.popAndPushNamed mengatasi kebutuhan tersebut dengan menghapus route aktif terlebih dahulu, lalu mendorong route baru sesuai nama yang diberikan.

dart Contoh: mengganti formulir dengan layar daftar
// tidak-dijalankan
Navigator.popAndPushNamed(context, '/');

Alternatif yang berakhir pada keadaan stack yang sama adalah pushReplacementNamed, yang mengganti route aktif tanpa tahap pop terpisah. Perbedaan keduanya terletak pada animasi transisi yang digunakan, sehingga pilihan dapat disesuaikan dengan efek yang diinginkan. Keduanya menjaga stack tetap ramping karena jumlah route tidak bertambah.

Meneruskan argumen#

Navigator.pushNamed menerima parameter opsional arguments yang boleh diisi nilai apa pun. Nilai itu disimpan pada RouteSettings milik route dan dapat dibaca dari layar tujuan. Contoh berikut meneruskan id catatan yang dipilih dalam bentuk bilangan bulat.

dart Contoh: meneruskan id catatan sebagai argumen
// tidak-dijalankan
Navigator.pushNamed(
  context,
  '/detail',
  arguments: 3,
);

Di layar tujuan, argumen dibaca melalui ModalRoute.of(context)!.settings.arguments. Tipe yang dikembalikan adalah Object?, sehingga nilai tersebut diubah ke tipe yang diharapkan melalui cast. Konversi inilah titik rapuh route bernama, sebab pemeriksa tipe tidak dapat memastikan isi argumen benar-benar sesuai.

Kegagalan yang muncul berupa error ketidakcocokan tipe saat cast dijalankan, misalnya nilai yang dikirim berupa string tetapi dibaca sebagai int. Tabel route tidak membawa informasi tipe argumen, sehingga bentuk argumen setiap route sebaiknya didokumentasikan di dekat tabelnya.

dart Contoh: membaca argumen di layar detail
// tidak-dijalankan
@override
Widget build(BuildContext context) {
  final id = ModalRoute.of(context)!.settings.arguments as int;
  return Scaffold(
    appBar: AppBar(title: Text('Catatan $id')),
    body: Text('Menampilkan isi catatan dengan id $id.'),
  );
}

onGenerateRoute dan route tak dikenal#

Tabel routes hanya memetakan nama tetap ke builder tetap, sehingga route yang membutuhkan data dinamis tidak dapat ditampung pada tabel tersebut. Callback onGenerateRoute dipanggil untuk setiap nama route yang tidak ditemukan pada tabel, lengkap dengan RouteSettings yang membawa nama dan argumennya. Callback ini mengembalikan objek Route yang disusun secara manual, misalnya MaterialPageRoute yang layarnya dibangun dari argumen yang sudah diurai.

dart Contoh: onGenerateRoute dan onUnknownRoute pada MaterialApp
// tidak-dijalankan
return MaterialApp(
  title: 'Catatan',
  routes: {
    '/': (context) => const LayarDaftarCatatan(),
  },
  onGenerateRoute: (settings) {
    if (settings.name == '/detail') {
      final id = settings.arguments as int?;
      return MaterialPageRoute(
        builder: (context) => LayarDetailCatatan(id: id ?? 0),
      );
    }
    return null;
  },
  onUnknownRoute: (settings) {
    return MaterialPageRoute(builder: (context) => const LayarDaftarCatatan());
  },
);

Apabila onGenerateRoute mengembalikan null karena nama yang diminta benar-benar tidak dikenali, callback yang dijalankan berikutnya adalah onUnknownRoute. Peran yang tepat bagi onUnknownRoute adalah sebagai pengalihan terakhir, misalnya mengembalikan pengguna ke layar daftar alih-alih membiarkan aplikasi gagal. Dengan pola ini, route dinamis dan route tak dikenal ditangani pada keluarga callback MaterialApp yang sama.

Pesan error yang muncul ketika nama route tidak tertangani adalah “Could not find a generator for route”. Pesan itu menandakan nama tidak ada pada tabel, onGenerateRoute tidak disediakan atau mengembalikan null, dan onUnknownRoute juga tidak ada. Menyediakan onUnknownRoute sejak awal membuat kasus ini tidak lagi berujung pada error saat aplikasi berjalan.

Kapan route bernama layak dipilih#

Route bernama unggul ketika aplikasi memiliki banyak layar yang namanya dipanggil dari banyak tempat, karena seluruh pemetaan terpusat pada satu tabel. Sebaliknya, aplikasi kecil dengan dua atau tiga perpindahan tidak memperoleh banyak manfaat, sedangkan biayanya nyata, yaitu string yang rawan salah ketik dan argumen bertipe Object? yang wajib di-cast. Tabel berikut merangkum kecocokan masing-masing pendekatan.

SituasiPendekatan yang lebih cocok
Sedikit perpindahan dan data diteruskan bertipe kuatNavigator.push dengan MaterialPageRoute
Banyak layar dengan nama yang dipanggil dari banyak tempattabel routes dengan pushNamed
Route dinamis yang butuh data saat dipanggilonGenerateRoute

Salah ketik pada nama route baru terdeteksi saat aplikasi berjalan, bukan saat kompilasi, karena tabel routes tidak memeriksa konsistensi string. Biaya tersebut perlu ditimbang ketika memilih antara pendekatan langsung dan route bernama.

Ringkasan#

  • Tabel routes pada MaterialApp memetakan nama route berbentuk string ke builder layar, dan kunci ‘/’ menjadi layar awal.
  • Navigator.pushNamed membuka route terdaftar, sedangkan Navigator.popAndPushNamed menghapus route aktif lalu membuka route baru.
  • Argumen diteruskan melalui parameter arguments, dibaca melalui ModalRoute.of(context)!.settings.arguments, dan wajib di-cast karena bertipe Object?.
  • onGenerateRoute menangani route dinamis di luar tabel, sedangkan onUnknownRoute menjadi pengalihan terakhir untuk nama yang tidak dikenal.

Referensi#