Praktikum Aplikasi Mobile 4 – Flutter

Navigation & Routing : Multiple Screen

Lihat Laporan

Pendahuluan

Tujuan Praktikum

  1. Membuat aplikasi yang dapat berpindah dari halaman satu ke halaman lain
  2. Membuat aplikasi yang dapat mengirim dan menerima data dari halaman lain

Routing

Pengertian

Routing atau Rute adalah sebuah sistem yang digunakan untuk mendefinisikan dan mengelola routes dalam aplikasi, setiap route didefinisikan sehingga Ketika akan memanggil halaman cukup dengan memanggil nama route tersebut, hal ini mempermudah dalam mengelola route tanpa harus membuat instance baru setiap kali akan memanggil suatu halaman.

Jenis - Jenis Routing

1. Navigator (Anonymous Routes)

Widget Navigation menampilkan halaman dengan konsep tumpukan menggunakan animasi transisi Ketika berpindah ke halaman, untuk berpindah ke halaman baru diakses melalui BuildContext dengan memanggil method seperti push() atau pop() secara langsung.

2. Named Routes

Named Routes atau Rute Bernama mengelola route pada widget MateriapApp atau CupertinoApp kemudian memanggilnya berdasarkan nama yang telah diberikan

3. Generated Routes

Generated Routes yang sebuah mekanisme mengelola routes dengan mengirimkan paremeter dan handle error.

4. Router / Navigator 2.0

Mekanisme pengelolaan routes ini digunakan jika aplikasi yang membutuhkan route yang komplek, biasanya digunakan Ketika membuat aplikasi web pada flutter.

Multiple Screen (Named Routes)

Pengertian

Saat kembali ke halaman sebelumnya, Flutter menggunakan pop() untuk menghapus halaman paling atas.

  1. Halaman Login
  2. Halaman Home
  3. Halaman Detail Produk
  4. Halaman Profile

Di Flutter, untuk berpindah antar halaman digunakan Navigator dan Routing.

  1. Navigator bertugas memindahkan (push) atau kembali (pop) dari satu halaman ke halaman lain
  2. Routing adalah sistem yang mengatur dan memberi nama setiap halaman agar bisa dipanggil dengan mudah.

Mengirim dan Menerima Data

Pengertian

Flutter memungkinkan kita mengirim data dari satu halaman ke halaman lain, contohnya:

  • Dari halaman Home ke halaman Profile, mengirim data seperti username dan ID pengguna..
  • Dari halaman Product List ke halaman Product Detail, mengirim data seperti nama produk dan harga.

Cara mengirim data ada 2 yaitu :

  1. Melalui Constructor yaitu data dikirim saat halaman baru dibuat
  2. Melalui Named Routes + Arguments yaitu data dikirim bersamaan dengan pemanggilan route.

Langkah Praktikum

1. Multiple screen

  • Buat file dart baru, disini saya menamakannya MyNav.dart lalu isikan dengan kode ini


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('Produk')),
      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'),
        ),
      ),
    );
  }
}

              

Berikut tampilan hasilnya.

Halaman Product

Halaman Product Detail

2. Mengirim dan Menerima Data antar Halaman

  • Buat file dart baru, disini saya menamakannya MyProfile.dart lalu isikan dengan kode ini


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(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const MyProfile(id: 1, name: 'Galid'),
                  ),
                );
              },
              child: const Text('Profile'),
            ),
            const SizedBox(width: 20),
            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')],
        ),
      ),
    );
  }
}

              

Berikut tampilan hasilnya.

Halaman Home

Halaman Profile menggunakan Constructor

Halaman Product menggunakan Named Routes

Tugas

Implementasi Basic Form Flutter


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(
      title: 'Tugas Navigation & Routing',
      initialRoute: '/',
      routes: {
        '/': (context) => const LoginPage(), // route '/' mengarah ke halaman Login
        '/home': (context) => const HomePage(), // route '/home' mengarah ke halaman utama
      },
    );
  }
}

//HALAMAN LOGIN 
class LoginPage extends StatefulWidget {
  const LoginPage({super.key});

  @override
  State createState() => _LoginPageState();
}

class _LoginPageState extends State {
  // Controller digunakan untuk mengambil teks dari TextField
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login Page')),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center, 
          children: [
            // Input field untuk username
            TextField(
              controller: _usernameController, // menghubungkan controller
              decoration: const InputDecoration(labelText: 'Username'),
            ),

            const SizedBox(height: 15), 
            // Input field untuk password
            TextField(
              controller: _passwordController,
              decoration: const InputDecoration(labelText: 'Password'),
              obscureText: true, // agar teks password tidak terlihat
            ),

            const SizedBox(height: 20),

            // Tombol login
            ElevatedButton(
              onPressed: () {
                // Ambil data dari TextField
                String username = _usernameController.text;
                String password = _passwordController.text;

                // Pindah ke halaman Home sambil mengirim data username dan password
                Navigator.pushNamed(
                  context,
                  '/home', // nama route tujuan
                  arguments: {
                    'username': username,
                    'password': password,
                  }, // data dikirim dalam bentuk Map
                );
              },
              child: const Text('Login'),
            ),
          ],
        ),
      ),
    );
  }
}

//HALAMAN HOME
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    // Menerima data dari halaman Login menggunakan ModalRoute
    final args = ModalRoute.of(context)!.settings.arguments as Map?;

    // Jika data ada, ambil nilai username dan password
    final username = args?['username'] ?? 'Unknown';
    final password = args?['password'] ?? 'Not set';

    return Scaffold(
      appBar: AppBar(title: const Text('Home Page')), 
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // Menampilkan data yang dikirim dari halaman Login
            Text(
              'Selamat Datang, $username!',
              style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 10),
            Text('Password Anda: $password'),
            const SizedBox(height: 30),
            const Text(
              'Contoh Navigasi Menggunakan Bottom Navigation Bar:',
              textAlign: TextAlign.center,
            ),
          ],
        ),
      ),

      // BOTTOM NAVIGATION BAR 
      // Salah satu contoh konsep navigation & routing bawaan Flutter
      bottomNavigationBar: BottomNavigationBar(
        // Daftar menu yang muncul di bawah layar
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
        ],

        // Aksi ketika salah satu menu ditekan
        onTap: (index) {
          if (index == 0) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Menu Home ditekan')),
            );
          } else if (index == 1) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Menu Profile ditekan')),
            );
          } else if (index == 2) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Menu Settings ditekan')),
            );
          }
        },
      ),
    );
  }
}
              

Berikut tampilan hasilnya.

Link Project

GitHub Repository