Flutter – Navigasi Antar Halaman

Untuk berpindah dari satu halaman ke halaman lainnya pada Flutter kita bisa menggunakan widget Navigator. Widget Navigator sendiri memiliki beberapa method untuk menangani beberapa skenario / kondisi. Pada tutorial ini saya akan membahas bagaimana menggunakan widget Navigator untuk menangani beberapa skenario / kondisi yang umumnya ada pada aplikasi mobile, seperti pindah halaman biasa, menangani tombol back, pindah halaman dengan membawa data dan menerima data dari halaman lainnya.

Navigasi Sederhana

Misal kita memiliki halaman / class simple seperti ini

import 'package:flutter/material.dart';

class Simple extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Simple Page'),
            ),
            body: Center(
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                        Text('Simple Page. Please press back button')
                    ],
                ),
            ),
        );
    }
}

Untuk pindah halaman, misal dari halaman home ke halaman simple diatas kita perlu melakukan beberapa hal, yaitu :

Import file

Misal halaman simple diatas disimpan di file simple.dart maka kita perlu import file tersebut di halaman home dengan kode seperti ini

import 'simple.dart';

Buat Action

Selanjutnya, masih di halaman home, kita perlu menentukan kapan aksi pindah halaman tersebut dilakukan. Pada umumnya aksi ini dipanggil saat user menekan tombol tertentu misal pada FlatButton seperti dibawah ini

FlatButton(
    onPressed: () {
        // pindah ke halaman simple
        Navigator.push(context, MaterialPageRoute(builder: (context) => Simple()));
    },
    child: Text(
        'Basic Navigation',
        style: TextStyle(
            color: Colors.white
        ),
    ),
    color: Colors.green,
),

Saat user menekan tombol Basic Navigation diatas, aplikasi akan menampilkan halaman baru yaitu halaman simple, jika user menekan tombol back maka akan kembali ke halaman sebelumnya yaitu home.

Navigasi tanpa History

Dengan Navigator kita juga bisa mencegah saat user menekan tombol back agar tidak kembali ke halaman sebelumnya. Misal pada halaman login, setelah user berhasil login dan masuk ke halaman dashboard misalnya, jika user menekan tombol back tentu kita tidak menginginkan untuk kembali ke halaman login lagi bukan ? Untuk menangani skenario ini kita bisa menggunakan method pushReplacement seperti dibawah ini

FlatButton(
    onPressed: () {
        // pindah ke halaman WithoutHistory
        // tapi tidak menyimpan halaman saat ini
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => WithoutHistory()));
    },
    child: Text(
        'Navigation Without History',
        style: TextStyle(
            color: Colors.white
        ),
    ),
    color: Colors.green,
),

Dengan method pushReplacement halaman saat ini, misal home tidak akan di cache di history. Di halaman baru jika user menekan tombol back aplikasi akan menampilkan halaman sebelum halaman saat ini (home) jika ada, jika tidak ada aplikasi akan otomatis ditutup.

Menangani Tombol Back

Misal pada suatu halaman user sudah memasukkan banyak data, lalu tidak sengaja menekan tombol back. Apa yang terjadi ? Tentu saja aplikasi akan kembali ke halaman sebelumnya dan data yang sudah dimasukkan user akan hilang. Untuk mencegah hal ini kita perlu meng-override tombol back. Agar kita bisa melakukan beberapa aksi, paling tidak menampilkan peringatan kepada user apakah yakin ingin keluar dari halaman sekarang atau tidak. Lalu data yang sudah dimasukkan mau di proses atau diabaikan.

Untuk menangani tombol back kita bisa menggunakan widget WillPopScope. Widget WillPopScope harus ditempatkan sebagai root widget sedangkan widget lainnya yang berhubungan dengan tampilan bisa ditempatkan sebagai child. Widget WillPopScope juga harus meng-initialize method onWillPop. Method onWillPop sendiri harus return Future<bool>. Jika return-nya true maka halaman akan ditutup, jika false tidak ada aksi. Berikut ini contoh penggunaaan widget WillPopScope.

import 'package:flutter/material.dart';

class HandleBack extends StatelessWidget {
    Future<bool> onBackButton(context) async {
        // tampilkan dialog saat user menekan tombol back
        // jika ditekan ok maka akan kembali ke halaman sebelumnya
        return showDialog(
            context: context,
            builder: (context){
                return AlertDialog(
                    title: Text('Back'),
                    content: Text('Are you sure want to back to previous page ?'),
                    actions: <Widget>[
                        FlatButton(
                            onPressed: () {
                                // tutup modal dan halaman ini
                                Navigator.of(context).pop(true);
                            },
                            child: Text('OK'),
                        ),
                        FlatButton(
                            onPressed: () {
                                // tutup modal saja
                                Navigator.of(context).pop(false);
                            },
                            child: Text('NO'),
                        )
                    ],
                );
            }
        );
    }

    @override
    Widget build(BuildContext context) {
        return WillPopScope(
            onWillPop: (){
                // panggil method onBackButton saat user menekan tombol back
                return onBackButton(context);
            },
            child: Scaffold(
                appBar: AppBar(
                    title: Text('Handle Back'),
                ),
                body: Center(
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                            Text('Try press back button')
                        ],
                    ),
                ),
            ),
        );
    }
}

Mengirim Data ke Halaman Baru

Untuk mengirim data dari halaman saat ini ke halaman baru kita cukup memasukkan data tersebut ke constructor halaman baru. Misal kita memiliki class seperti ini

import 'package:flutter/material.dart';
import 'customer.dart';

class ReceiptData extends StatefulWidget {
    // property
    final Customer customer;

    // constructor
    ReceiptData({Key key, @required this.customer}) : super(key: key);

    @override
    _ReceiptDataState createState() => _ReceiptDataState(customer: customer);
}

class _ReceiptDataState extends State<ReceiptData> {
    // property
    Customer customer;

    // constructor
    _ReceiptDataState({@required this.customer}) : super();

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Receipt Data'),
            ),
            body: Center(
                child: Padding(
                    padding: EdgeInsets.all(20),
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                            Text(
                                'Inserted Customer : '
                            ),
                            Text(
                                'Name: ' + customer.name
                            ),
                            Text(
                                'Address: ' + customer.address
                            ),
                        ],
                    ),
                )
            ),
        );
    }
}

Untuk mengirim data customer ke halaman ReceiptData diatas kita bisa menggunakan kode seperti ini.

Customer customer = Customer(nameController.text, addressController.text);
Navigator.push(context, MaterialPageRoute(builder: (context) => ReceiptData(customer: customer)));

Kode lengkapnya seperti dibawah ini

Class Customer

class Customer {
    String name;
    String address;

    Customer(String name, String address){
        this.name = name;
        this.address = address;
    }
}

Class ReceiptData. Menerima data dari halaman sebelumnya.

import 'package:flutter/material.dart';
import 'customer.dart';

class ReceiptData extends StatefulWidget {
    // property
    final Customer customer;

    // constructor
    ReceiptData({Key key, @required this.customer}) : super(key: key);

    @override
    _ReceiptDataState createState() => _ReceiptDataState(customer: customer);
}

class _ReceiptDataState extends State<ReceiptData> {
    // property
    Customer customer;

    // constructor
    _ReceiptDataState({@required this.customer}) : super();

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Receipt Data'),
            ),
            body: Center(
                child: Padding(
                    padding: EdgeInsets.all(20),
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                            Text(
                                'Inserted Customer : '
                            ),
                            Text(
                                'Name: ' + customer.name
                            ),
                            Text(
                                'Address: ' + customer.address
                            ),
                        ],
                    ),
                )
            ),
        );
    }
}

Class CollectData. Menerima input user kemudian kirim ke halaman ReceiptData.

import 'package:flutter/material.dart';
import 'customer.dart';
import 'receipt_data.dart';

class CollectData extends StatefulWidget {
    CollectData({Key key}) : super(key: key);

    @override
    _CollectDataState createState() => _CollectDataState();
}

class _CollectDataState extends State<CollectData> {
    TextEditingController nameController = TextEditingController();
    TextEditingController addressController = TextEditingController();

    bool isValid(){
        if(nameController.text.isEmpty){
            return false;
        }

        if(addressController.text.isEmpty){
            return false;
        }

        return true;
    }

    sendData() {
        if(isValid()){
            // buat object customer dari input user
            Customer customer = Customer(nameController.text, addressController.text);
            // kirim object customer ke halaman ReceiptData
            Navigator.push(context, MaterialPageRoute(builder: (context) => ReceiptData(customer: customer)));
        }else{
            return showDialog(
                context: context,
                builder: (context){
                    return AlertDialog(
                        content: Text('Please fill all field.'),
                        actions: <Widget>[
                            FlatButton(
                                onPressed: () {
                                    Navigator.pop(context);
                                },
                                child: Text('OK'),
                            ),
                        ],
                    );
                }
            );
        }
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Collect Data'),
                actions: <Widget>[
                    FlatButton(
                        onPressed: (){
                            sendData();
                        },
                        child: Text(
                            'SEND',
                            style: TextStyle(
                                color: Colors.white
                            ),
                        ),
                    )
                ],
            ),
            body: Center(
                child: Padding(
                    padding: EdgeInsets.all(20),
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                            Text(
                                'Name'
                            ),
                            TextField(
                                controller: nameController,
                            ),
                            Padding(
                                padding: EdgeInsets.only(top: 20),
                            ),
                            Text(
                                'Address'
                            ),
                            TextField(
                                controller: addressController,
                            )
                        ],
                    ),
                )
            ),
        );
    }
}

Menerima Data dari Halaman Baru

Dengan method Navigator.pop() kita bisa mengirim balik data ke halaman sebelumnya dengan cara memasukkan data tersebut sebagai argument. Seperti kode dibawah ini

// buat object customer dari input user
Customer customer = Customer(nameController.text, addressController.text);
// kirim object customer ke halaman sebelumnya
Navigator.pop(context, customer);

Sedangkan pada halaman sebelumnya (halaman pemanggil) kita bisa menerima data dari halaman baru dengan kode dibawah ini

waitForData() async {
    // pada dasarnya method Navigator.push return Future
    // jadi kita bisa menggunakan await untuk mendapatkan data sebenarnya
    // bisa juga menggunakan method then()
    Customer customer = await Navigator.push(context, MaterialPageRoute(builder: (context) => SendDataBack()));

    String content = '';

    // cek data yang diterima null atau tidak
    // jika user menekan tombol back data akan bernilai null
    if(customer != null){
        content = 'You insert Name : ${customer.name} and Address : ${customer.address}';
    }else{
        content = 'Please insert Name and Address';
    }
    return showDialog(
        context: context,
        builder: (context){
            return AlertDialog(
                content: Text(content),
                actions: <Widget>[
                    FlatButton(
                        onPressed: () {
                            Navigator.pop(context);
                        },
                        child: Text('OK'),
                    ),
                ],
            );
        }
    );
}

Download Source Code & Apk

Leave a Reply

Your email address will not be published. Required fields are marked *