Navigasi dan Routing
Navigation 1.0
Pemrograman Mobile
Muhamad Saad Nurul Ishlah, M.Comp.
Dept. Sistem Informasi & Dept. Ilmu Komputer, Universitas Pakuan
Agenda Kuliah
- Menavigasi ke layar baru dan kembali
- Menavigasi menggunakan rute bernama
- Meneruskan argumen ke rute bernama
- Mengembalikan data dari layar baru
- Mengirim data ke layar baru
Menavigasi ke Layar Baru dan Kembali
Menavigasi ke Layar Baru dan Kembali
- Sebagian besar aplikasi memiliki banyak layar yang bertujuan untuk memunculkan informasi berbeda
- Contoh: Aplikasi eCommerce – Layar produk > tap gambar > tampilkan detil produk
- Routing – Menavigasi dari satu layar ke layar yang lain
- Terminologi:
- Route (Rute) = Layar atau Halaman
- Route = Activity (Android)
- Route = ViewController (iOS)
- Route = Widget (Flutter)
- Widget Navigator digunakan untuk menavigasi ke rute baru
- Navigator 1.0 – Imperative API, Navigator 2.0 – Declarative
- Package – go_router
Navigator 1.0
- Navigator – Widget yang mengelola tumpukan objek Route
- Route – objek yang dikelola oleh Navigator yang merepresentasikan layar, biasanya diimplementasikan menggunakan kelas, seperti MaterialPageRoute
- Mekanisme navigasi – objek Route didorong (pushed - push) dan dikeluarkan (popped - pop) dari tumpukan di Navigator
- Navigator.push() atau Navigator.pushNamed()
- Navigator.pop()
- Jenis Routing:
- Anonymous Routes – Rute tidak bernama
- Named Routes – Rute bernama
Navigator 1.0
- Navigator – Widget yang mengelola tumpukan objek Route
- Route – objek yang dikelola oleh Navigator yang merepresentasikan layar, biasanya diimplementasikan menggunakan kelas, seperti MaterialPageRoute
- Mekanisme navigasi – objek Route didorong (pushed - push) dan dikeluarkan (popped - pop) dari tumpukan di Navigator
- Navigator.push() atau Navigator.pushNamed()
- Navigator.pop()
- Jenis Routing:
- Anonymous Routes – Rute tidak bernama
- Named Routes – Rute bernama
Anonymous Routes
- MaterialApp dan CupertinoApp menggunakan Navigator secara default – gunakan langsung
- Navigator.push() digunakan untuk beralih ke rute tertentu
- Metode push() menambahkan Route ke tumpukan Route yang dikelola oleh Navigator
- Navigator.pop() digunakan untuk kembali ke layar sebelumnya
- Mengeluarkan Route dari tumpukan
Anonymous Routes
- Navigator.push()
- Route dapat menggunakan MaterialPageRoute
@optionalTypeArgs
Future<T?> push<T extends Object?>(
BuildContext context,
Route<T> route
)
@optionalTypeArgs
Anonymous Routes
class FirstRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
),
),
);
}
}
class SecondRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
Pindah ke layar baru (SecondRoute)
Kembali ke layar sebelumnya (FirstRoute)
Anonymous Routes
Anonymous Routes
Navigasi dengan Rute Bernama
(Named Routes)
Membuka layar yang sama dari bagian lain di aplikasi?
Membuka layar yang sama dari bagian lain di aplikasi?
anonymous routes – duplikasi kode
Named Routes
- Menamai Route untuk kebutuhan navigasi
- Gunakan Navigator.pushNamed() untuk beralih ke rute tertentu
- Gunakan Navigator.pop() untuk kembali
@optionalTypeArgs
Future<T?> pushNamed <T extends Object?>(
BuildContext context,
String routeName,
{Object? arguments}
)
@optionalTypeArgs
Named Routes
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Named Routes Demo',
// Start the app with the "/" named route. In this case, the app starts
// on the FirstScreen widget.
initialRoute: '/',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => FirstScreen(),
// When navigating to the "/second" route, build the SecondScreen widget.
'/second': (context) => SecondScreen(),
},
),
);
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: ElevatedButton(
// Within the `FirstScreen` widget
onPressed: () {
// Navigate to the second screen using a named route.
Navigator.pushNamed(context, '/second');
},
child: Text('Launch screen'),
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: ElevatedButton(
// Within the SecondScreen widget
onPressed: () {
// Navigate back to the first screen by popping the current route
// off the stack.
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
Menggunakan Named Routes
- Definisikan Routes pada widget MaterialApp atau CupertinoApp
- Definisikan rute inisial (initialRoute)
- List semua route yang bisa dilakukan – beri nama (Dictionary)
- Gunakan route dalam widget interaktif sebagai fungsi callback
Named Routes
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Named Routes Demo',
// Start the app with the "/" named route. In this case, the app starts
// on the FirstScreen widget.
initialRoute: '/',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => FirstScreen(),
// When navigating to the "/second" route, build the SecondScreen widget.
'/second': (context) => SecondScreen(),
},
),
);
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: ElevatedButton(
// Within the `FirstScreen` widget
onPressed: () {
// Navigate to the second screen using a named route.
Navigator.pushNamed(context, '/second');
},
child: Text('Launch screen'),
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: ElevatedButton(
// Within the SecondScreen widget
onPressed: () {
// Navigate back to the first screen by popping the current route
// off the stack.
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
Kembali ke layar pertama
- Panggil Navigator.pop(context) untuk kembali ke layar awal
Named Routes
Named Routes
Peringatan:
Saat menggunakan initialRoute, jangan tentukan properti home.
Meneruskan Argumen ke Rute Bernama
Meneruskan Argumen
- Navigator menyediakan kemampuan untuk beralih ke rute lain
- Dalam beberapa kasus, perlu meneruskan argumen ke rute bernama
- Bagaimana caranya?
- Gunakan parameter arguments pada metode Navigator.pushNamed()
- Ekstrak argumen menggunakan metode ModalRoute.of atau dalam fungsi onGenerateRoute()
@optionalTypeArgs
Future<T?> pushNamed <T extends Object?>(
BuildContext context,
String routeName,
{Object? arguments}
)
@optionalTypeArgs
Meneruskan & Mengekstrak Argumen (ModalRoute.of())
// You can pass any object to the arguments parameter.
// In this example, create a class that contains both
// a customizable title and message.
class ScreenArguments {
final String title;
final String message;
ScreenArguments(this.title, this.message);
}
// A Widget that extracts the necessary arguments from
// the ModalRoute.
class ExtractArgumentsScreen extends StatelessWidget {
static const routeName = '/extractArguments';
@override
Widget build(BuildContext context) {
// Extract the arguments from the current ModalRoute
// settings and cast them as ScreenArguments.
final ScreenArguments args =
ModalRoute.of(context)!.settings.arguments as ScreenArguments;
return Scaffold(
appBar: AppBar(
title: Text(args.title),
),
body: Center(
child: Text(args.message),
),
);
}
}
// Register the widget in the routes
MaterialApp(
routes: {
ExtractArgumentsScreen.routeName: (context) => ExtractArgumentsScreen(),
},
)
// A button that navigates to a named route.
// The named route extracts the arguments
// by itself.
ElevatedButton(
child: Text("Navigate to screen that extracts arguments"),
onPressed: () {
// When the user taps the button,
// navigate to a named route and
// provide the arguments as an optional
// parameter.
Navigator.pushNamed(
context,
ExtractArgumentsScreen.routeName,
arguments: ScreenArguments(
'Extract Arguments Screen',
'This message is extracted in the build method.',
),
);
},
),
Langkah-langkah
- Definisikan argumen yang ingin diteruskan – berupa objek
- Buat widget yang akan mengekstrak argumen yang diteruskan
- Daftarkan widget sebagai route
- Navigasi ke widget
Meneruskan & Mengekstrak Argumen (onGenerateRoute)
MaterialApp(
// Provide a function to handle named routes.
// Use this function to identify the named
// route being pushed, and create the correct
// Screen.
onGenerateRoute: (settings) {
// If you push the PassArguments route
if (settings.name == PassArgumentsScreen.routeName) {
// Cast the arguments to the correct
// type: ScreenArguments.
final ScreenArguments args = settings.arguments as ScreenArguments;
// Then, extract the required data from
// the arguments and pass the data to the
// correct screen.
return MaterialPageRoute(
builder: (context) {
return PassArgumentsScreen(
title: args.title,
message: args.message,
);
},
);
}
// The code only supports
// PassArgumentsScreen.routeName right now.
// Other values need to be implemented if we
// add them. The assertion here will help remind
// us of that higher up in the call stack, since
// this assertion would otherwise fire somewhere
// in the framework.
assert(false, 'Need to implement ${settings.name}');
return null;
},
)
Daripada mengesktrak langsung di widget, argumen dapat diekstrak dengan menggunakan fungsi onGenerateRoute() dan meneruskannya ke widget
Meneruskan & Mengekstrak Argumen
Mengembalikan Data dari Layar Baru
Mengembalikan Data dari Layar Baru
- Dalam banyak kasus, kita butuh mengembalikan data dari layar baru kembali ke layar sebelumnya
- Contoh:
- Push layar baru > 2 opsi > tap opsi > kembali ke layar dengan data opsi
- Navigator.pop()
@optionalTypeArgs
void pop <T extends Object?>(
BuildContext context,
[T? result]
)
@optionalTypeArgs
Mengembalikan Data dari Layar Baru
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
// Create the SelectionButton widget in the next step.
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Text('Pick an option, any option!'),
);
}
// A method that launches the SelectionScreen and awaits the
// result from Navigator.pop.
_navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that completes after calling
// Navigator.pop on the Selection Screen.
final result = await Navigator.push(
context,
// Create the SelectionScreen in the next step.
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
}
class SelectionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () {
// The Yep button returns "Yep!" as the result.
Navigator.pop(context, 'Yep!');
},
child: Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () {
// The Nope button returns "Nope!" as the result.
Navigator.pop(context, 'Nope!');
},
child: Text('Nope.'),
),
)
],
),
),
);
}
}
Langkah-langkah:
- Definisikan layar home
- Buat widget yang melakukan hal berikut:
- Membuka layar baru
- Menunggu layar baru mengembalikan hasil
- Buat layar yang menyediakan opsi data
- Gunakan data yang dikembalikan pada layar awal
Mengembalikan Data dari Layar Baru
Mengirim Data ke Layar Baru
Mengirim Data ke Layar Baru
- Layar merupakan Widget
- Dua opsi
- Widget dapat diberikan argumen ketika inisiasi objek baru pada bagian Constructor. Data dapat dikirimkan ketika menginisiasi objek widget baru
- RouteSettings – ModalRoute.of. Butuh ektraksi di layar baru
Mengirim Data ke Layar Baru (Constructor)
https://gist.github.com/nurulishlah/0b9239de66a366cb60e0500224da421d
Mengirim Data ke Layar Baru (RouteSettigns)
Diskusi
Ada pertanyaan?
Referensi
- Ryan, John. “Learning Flutter’s New Navigation and Routing System.” Flutter Medium, 30 Sept. 2020, medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade. diakses: 10 April 2021
- Windmill, Eric. 2020. Flutter in Action. Manning Publications.
- https://flutter.dev/docs/cookbook#navigation. diakses: 10 April 2021
Terima Kasih
Navigasi dan Routing
By Muhamad Ishlah
Navigasi dan Routing
- 4,626