Konsep Navigation & Routing Flutter
Navigation
Proses berpindah dari satu halaman (screen/page) ke halaman lain dalam aplikasi Flutter. Menggunakan konsep tumpukan (stack) dengan widget Navigator.
Routing
Sistem untuk mendefinisikan dan mengelola routes dalam aplikasi. Mempermudah pengelolaan route tanpa membuat instance baru setiap kali memanggil halaman.
Push & Pop
Push: Menambahkan halaman baru ke tumpukan navigasi. Pop: Mengeluarkan halaman saat ini dari tumpukan dan kembali ke halaman sebelumnya.
Data Passing
Mengirim dan menerima data antar halaman menggunakan constructor atau arguments melalui named routes.
Langkah Implementasi sesuai Modul
Navigation Dasar dengan Named Routes
Implementasi navigasi sederhana antara halaman Product dan ProductDetail:
import 'package:flutter/material.dart';
void main() => runApp(const MyNav());
class MyNav extends StatelessWidget {
const MyNav({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const Product(),
'/product_detail': (context) => const ProductDetail(),
},
);
}
}
class Product extends StatelessWidget {
const Product({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Product')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/product_detail');
},
child: const Text('Go to Product Detail'),
),
),
);
}
}
class ProductDetail extends StatelessWidget {
const ProductDetail({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Product Detail')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Back to Product'),
),
),
);
}
}
Dokumentasi Implementasi:
Halaman Product
Halaman Product Detail
Mengirim dan Menerima Data antar Halaman
Implementasi pengiriman data menggunakan constructor dan named routes:
import 'package:flutter/material.dart';
void main() => runApp(MyNav());
class MyNav extends StatelessWidget {
const MyNav({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const HomePage(),
'/product': (context) => const MyProduct(),
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Page')),
body: Center(
child: Row(
children: [
// Mengirim data dengan constructor
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const MyProfile(id: 1, name: 'Rifki'),
),
);
},
child: const Text('Profile'),
),
// Mengirim data dengan named routes
ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
'/product',
arguments: {'id': 101, 'name': 'Laptop'},
);
},
child: const Text('Product'),
),
],
),
),
);
}
}
class MyProfile extends StatelessWidget {
final int id;
final String name;
const MyProfile({super.key, required this.id, required this.name});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Profile')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('ID: $id'),
Text('Name: $name'),
],
),
),
);
}
}
class MyProduct extends StatelessWidget {
const MyProduct({super.key});
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as Map?;
final int id = args?['id'] ?? 0;
final String name = args?['name'] ?? 'Unknown';
return Scaffold(
appBar: AppBar(title: const Text('Product')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Product ID: $id'),
Text('Product Name: $name'),
],
),
),
);
}
}
Dokumentasi Data Passing:
Halaman Home
Profile (Constructor)
Product (Named Routes)
Tugas: Aplikasi Login dengan Navigation dan Drawer
Implementasi Halaman Login dan Navigation
Berikut adalah implementasi aplikasi login dengan navigation dan drawer:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const LoginPage(),
'/home': (context) => const HomePage(),
},
);
}
}
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State createState() => _LoginPageState();
}
class _LoginPageState extends State {
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
void _login() {
String username = _usernameController.text;
String password = _passwordController.text;
Navigator.pushNamed(
context,
'/home',
arguments: {'username': username, 'password': password},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _usernameController,
decoration: const InputDecoration(labelText: 'Username'),
),
TextField(
controller: _passwordController,
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
),
const SizedBox(height: 20),
ElevatedButton(onPressed: _login, child: const Text('Login')),
],
),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as Map?;
final username = args?['username'] ?? '';
final password = args?['password'] ?? '';
return Scaffold(
appBar: AppBar(title: const Text('Halaman Utama')),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration: const BoxDecoration(color: Colors.blue),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Menu',
style: TextStyle(color: Colors.white, fontSize: 24),
),
const SizedBox(height: 10),
Text(
'Username: $username',
style: const TextStyle(color: Colors.white),
),
],
),
),
ListTile(
leading: const Icon(Icons.person),
title: const Text('Profile'),
onTap: () {
Navigator.pop(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Profile'),
content: Text('Username: $username\nPassword: $password'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
),
],
),
);
},
),
ListTile(
leading: const Icon(Icons.info),
title: const Text('About'),
onTap: () {
Navigator.pop(context);
showAboutDialog(
context: context,
applicationName: 'Aplikasi Praktikum',
applicationVersion: '1.0.0',
applicationLegalese: '© 2025 MyApp',
children: [
const Padding(
padding: EdgeInsets.only(top: 16.0),
child: Text(
'Aplikasi ini dibuat untuk praktikum Navigation & Routing Flutter.',
),
),
],
);
},
),
ListTile(
leading: const Icon(Icons.logout),
title: const Text('Logout'),
onTap: () {
Navigator.pop(context);
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
],
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Username: $username'),
Text('Password: $password')
],
),
),
);
}
}
Dokumentasi Tugas:
Halaman Login
Halaman Utama
Halaman Utama dengan Drawer
Dialog Profile
Dialog About
Kesimpulan
Dalam praktikum Navigation & Routing Flutter ini, kita telah mempelajari:
- Konsep dasar navigation dan routing dalam Flutter menggunakan stack
- Implementasi navigasi sederhana dengan named routes antara halaman
- Teknik mengirim dan menerima data antar halaman menggunakan constructor dan arguments
- Pembuatan aplikasi login dengan mekanisme navigasi yang kompleks
- Implementasi drawer navigation dengan berbagai menu dan dialog
- Penggunaan widget-widget navigation seperti AlertDialog dan AboutDialog
Pemahaman tentang navigation dan routing sangat penting dalam pengembangan aplikasi Flutter karena memungkinkan kita membuat aplikasi dengan multiple screen yang terstruktur dan mudah dikelola. Dengan menguasai konsep ini, kita dapat membuat user experience yang lebih baik dengan transisi yang smooth antar halaman.
Untuk kode lengkap praktikum dapat diakses pada repository GitHub: https://github.com/Alone1011/2311532011-RifkiY-MobileApp.git