Flutter Tutorial: Membuat Bottom Navigation Bar Dengan Riverpod

Pengantar
Selamat datang di tutorial pembuatan bottom navigation bar dengan menggunakan Riverpod di Flutter! Bottom navigation bar adalah bagian penting dari banyak aplikasi Flutter karena memungkinkan pengguna untuk dengan mudah beralih antara beberapa tampilan atau layar. Dalam tutorial ini, kita akan belajar cara membuat bottom navigation bar yang indah dan responsif menggunakan Riverpod, sebuah package manajemen state yang kuat untuk Flutter.

Apa yang Akan Anda Pelajari
  • Cara menggunakan Riverpod untuk mengelola state dalam aplikasi Flutter.
  • Membuat bottom navigation bar dengan item navigasi yang dapat diubah.
  • Menampilkan konten yang berbeda tergantung pada item navigasi yang dipilih.
Persyaratan
  • Pengetahuan dasar tentang Flutter dan Dart.
  • Pengaturan Flutter SDK dan editor Flutter yang telah terinstal.
Jika Anda siap, mari kita mulai!

Langkah 1: Persiapan Proyek

Pastikan Anda telah membuat proyek Flutter baru atau menggunakan proyek yang ada. Anda dapat membuka terminal pada komputer Anda kemudian membuat proyek Flutter baru dengan perintah seperti berikut:
flutter create nama_proyek_flutter
Lalu buka proyek tersebut di editor Flutter pilihan Anda. 

Langkah 2: Menambahkan Dependensi

Tambahkan dependensi flutter_riverpod ke dalam file pubspec.yaml Anda:
dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^1.0.4

Langkah 3: Membuat Bottom Navigation Bar

Sekarang, mari kita buat bottom navigation bar dengan Riverpod! Bottom navigation bar kita akan memiliki tiga item navigasi: "Home", "Search", dan "Profile".
Kita akan menggunakan tiga widget yang berbeda untuk mewakili setiap halaman.

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Retro Dev Bottom Nav Bar',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const BottomNav(),
    );
  }
}

class BottomNav extends ConsumerWidget {
  const BottomNav({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bottom Navigation'),
      ),
      body: const Center(
        child: Text('Home Page'),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: 0,
        onTap: (index) {},
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'Search',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}
Berikut hasilnya:

Langkah 4: Menggunakan Provider untuk Menyimpan State

Kita akan menggunakan provider StateProvider untuk menyimpan indeks halaman yang aktif di dalam bottom navigation bar. Tambahkan kode berikut ini diatas class MyApp.
final selectedIndexProvider = StateProvider((ref) => 0);
Seperti yang Anda lihat di atas, saya membuat satu variabel bernama selectedIndexProvider, variabel itu akan kita gunakan untuk indeks navbar. Tapi bagaimana caranya? Jangan khawatir, saya akan menunjukkan cara kerjanya. Kita perlu memanggil selectedIndexProvider ke halaman kita terlebih dahulu dan menamai variabelnya dengan selectedIndex. Anda dapat menyalin dan menempelkan kode saya di bawah ini dan meletakkannya dengan benar pada metode build.
final selectedIndex = ref.watch(selectedIndexProvider);
Kemudian kita ubah properti currentIndex pada widget BottomNavigationBar:
currentIndex: indexBottomNavbar,
Sehingga kode pada widget BottomNav menjadi seperti dibawah ini:
class BottomNav extends ConsumerWidget {
  const BottomNav({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedIndex = ref.watch(selectedIndexProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bottom Navigation'),
      ),
      body: const Center(
        child: Text('Home Page'),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: selectedIndex,
        onTap: (index) {},
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'Search',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}
Jika Anda menjalankan kode diatas, maka akan melihat kesalahan di layar seperti ini:
Jangan kuatir, masalah ini muncul karena kita tidak memanggil providerscope di pohon widget kita. Solusi untuk masalah ini sangat sederhana, kita hanya perlu menggabungkan widget MyApp kita dengan ProviderScope. Metode utama Anda di main.dart akan terlihat seperti:
void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}
Selanjutnya lakukan hot restart atau jalankan ulang aplikasi, dan kesalahannya akan hilang.

Langkah 5: Mengganti Halaman Saat Pengguna Menekan Item Navigasi

Kita akan menggunakan ConsumerWidget untuk membuat widget BottomNav yang akan merespons perubahan pada provider selectedIndexProvider. Ketika pengguna menekan salah satu item pada bottom navigation bar, kita akan memperbarui nilai selectedIndexProvider menggunakan ref.read. Perhatikan pada properti onTap pada widget BottomNav. Pada properti onTap tersebut, kita cukup memanggil metode ref.read dari WidgetRef, dan mengubah nilai state-nya. Ubah pada properti onTap menjadi seperti berikut dan coba klik di menu item navigasi lainnya maka akan berubah.
onTap: (index) {
   ref.read(selectedIndexProvider.notifier).state = index;
},

Langkah 6: Menampilkan Konten yang Sesuai

Kita akan menggunakan nilai indeks yang disimpan dalam provider selectedIndexProvider untuk menampilkan konten yang sesuai di dalam halaman utama aplikasi. Pada menu navigasi terdapat 3 menu, yaitu "Home", "Search", dan "Profile". Kita perlu menambahkan atau membuat ketiga halaman tersebut agar tiap menu navigasi dapat menampilkan konten yang sesuai dengan nama menu navigasinya. Tambahkan kode berikut dibawah class BottomNav.
class Page {
  final String title;
  final Widget widget;

  Page({required this.title, required this.widget});
}

class HomePage extends ConsumerWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container(
      color: Colors.blue,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Home Page',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            ElevatedButton(
              onPressed: () {
                ref.read(selectedIndexProvider.notifier).state = 2; // Navigasi ke Profil
              },
              child: Text('Go to Profile Page'),
            ),
          ],
        ),
      ),
    );
  }
}

class SearchPage extends ConsumerWidget {
  const SearchPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container(
      color: Colors.green,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Search Page',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            ElevatedButton(
              onPressed: () {
                ref.read(selectedIndexProvider.notifier).state = 0; // Navigasi ke Home
              },
              child: Text('Go to Home Page'),
            ),
          ],
        ),
      ),
    );
  }
}

class ProfilePage extends ConsumerWidget {
  const ProfilePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container(
      color: Colors.orange,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Profile Page',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            ElevatedButton(
              onPressed: () {
                ref.read(selectedIndexProvider.notifier).state = 1; // Navigasi ke Search
              },
              child: Text('Go to Search Page'),
            ),
          ],
        ),
      ),
    );
  }
}
Kemudian pada class BottomNav kita perlu menambahkan variabel pages yang menampung ketika halaman yang telah kita buat diatas. Tambahkan kode berikut dibawah variabel selectedIndex pada class BottomNav.
final List<Page> pageList = [
    Page(
      title: 'Home Page',
      widget: HomePage(),
    ),
    Page(
      title: 'Search Page',
      widget: SearchPage(),
    ),
    Page(
      title: 'Profile Page',
      widget: ProfilePage(),
    ),
  ];
Jangan lupa untuk mengubah properti body Scaffold pada class BottomNav menjadi variabel pagesList seperti berikut ini agar konten masing-masing menu navigasi dapat berubah dan sesuai dengan halaman yang telah kita buat sebelumnya.
body: pageList[selectedIndex].widget,
Sehingga kode pada widget BottomNav menjadi seperti dibawah ini:
class BottomNav extends ConsumerWidget {
  const BottomNav({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedIndex = ref.watch(selectedIndexProvider);
    final List<Page> pageList = [
      Page(
        title: 'Home Page',
        widget: HomePage(),
      ),
      Page(
        title: 'Search Page',
        widget: SearchPage(),
      ),
      Page(
        title: 'Profile Page',
        widget: ProfilePage(),
      ),
    ];

    return Scaffold(
      appBar: AppBar(
        title: const Text('Bottom Navigation'),
      ),
      body: pageList[selectedIndex].widget,
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: selectedIndex,
        onTap: (index) {
          ref.read(selectedIndexProvider.notifier).state = index;
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'Search',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}
Dan taraaa... Hasilnya seperti berikut:
Kita sudah menambahkan tombol yang dapat digunakan untuk berpindah-pindah halaman pada tiap halaman. Sehingga mungkin dalam kondisi tertentu Anda perlu berpindah halaman menggunakan tombol, Anda dapat menggunakan cara diatas.

Untuk source code selengkapnya dapat dicek pada github DISINI.

Sekian tutorial kali ini, terimakasih telah membaca.



a
Techy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ART
Techy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ARTTechy Pranav PKD ART