【Flutter】RiverpodとNavigationBarをシンプルに実装(iOS)

flutter

2023年時点でメジャーな状態管理フレームワークのRiverpodとNavigationBarを使用してRiverpodの理解を深めたいと思い備忘録としてここに記載します。(2023.04時点)

完成図

真ん中にTextを表示したシンプルなアプリです。

構成

構成については以下の通りです。

  • main.dart: NavigationBarを管理
  • first.dat: 最初のページ
  • second.dart: 次のページ

子ページの実装

メインの管理ページの前に各ページの簡単な設定を記載します。
(CenterウィジェットでTextを表示させてるだけですw)

class FirstPage extends StatelessWidget {
  const FirstPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('home'),
      ),
    );
  }
}

ライブラリインポート

Fluttetrのライブラリ使用ではお馴染みのpubspec.yamlへのインポートを行います。

dependencies:
  flutter:
    sdk: flutter

  flutter_riverpod: ^2.3.2

ProvierScopeのラッピング

Riverpodを使用するためにmain関数をProvierScopeでラッピングします。
これは使用するために必要なことぐらいの認識で良いかなと思います。

void main() {
  runApp(ProviderScope(child: MyApp()));
}

RiverpodでNavBarを管理するための5つの設定

このアプリの核となるポイントは以下の5つかなと思います。

  1. StateProviderの宣言
  2. watchでのProvider取得
  3. NavigationBarの本体実装
  4. currentIndex実装
  5. タップした際の処理

StateProviderの宣言

プロバイダーを使用するためにグローバルに宣言します。
Riverpodはプロバイダーひとつに対して複数のWidgetの管理に最適なフレームワークです。

そのためグローバルに宣言しています。

今回はViewTypeという配列を用意しています。
初期値にfirstという文字列を設定しています。

final provider = StateProvider((ref) => ViewType.first);

//  indexを表示するようの配列
enum ViewType {first, second}

watchでのProvider取得

先ほど宣言したProviderを実際に取得(listen)する変数を設定します。
ここでprovider.notifierとすると後で値が更新できないためref.watchの中身をprovider.stateとする必要があります。

  Widget build(BuildContext context, WidgetRef ref) {
    // ref.watch(provider.notifier): StateNotifierを取得するだけでステートのlistenはしない

    var view = ref.watch(provider.state);

NavigationBarの本体実装

実際の画面に当たる部分です。
各ページ(CenterにTextを表示させてるだけのページたち)の配列pagesを作成します。

  final pages = [
    FirstPage(),
    SecondPage()
  ];

そしてbodyに設置します。[]にあたる何番目のものを表示するかの部分にproviderで取得したものを使用します。

view.stateのインデックス番目のものを画面に表示しています。
これでview.state.indexが更新されればタブが更新できるようになります。

      home: Scaffold(
        body: pages[view.state.index],

currentIndex実装

BottomNavigationBarの今いる場所を宣言します。
上のbodyの部分は実際にはこちらを宣言しないと今いる場所が設定できていないために切り替わりません。

こちらもviewで取得したステートのインデックスを設定します。

          currentIndex: view.state.index,

タップした際の処理

タップした際の処理になります。
ここでタップした際に値を更新しています。

ここでのindexという引数は選択されたタブが何番目かを示しています。
なので選択されたタブ番目(表現が微妙ですみませんmm)のViewTypeをviewに代入してあげることでタブの切り替えが可能になります。

ViewType.valuesは配列の中身であるfirstとsecondの文字列のことです。

          onTap: (int index){
            // watchで取ってきたステート(viewのstate)にタップされた引数(index)番目のViewTypeを代入する
            view.state = ViewType.values[index];
            },

全体の実装

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:test_nabbar_riverpod/first.dart';
import 'package:test_nabbar_riverpod/second.dart';

final provider = StateProvider((ref) => ViewType.first);

//  indexを表示するようの配列
enum ViewType {first, second}

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends ConsumerWidget {
   MyApp({Key? key}) : super(key: key);

  final pages = [
    FirstPage(),
    SecondPage()
  ];

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // ref.watch(provider.state): StateNotifierを取得しステートをlistenする
    // ref.watch(provider.notifier): StateNotifierを取得するだけでステートのlistenはしない


    var view = ref.watch(provider.state);
    return MaterialApp(
      home: Scaffold(
        body: pages[view.state.index],
        bottomNavigationBar: BottomNavigationBar(
          items: [
            BottomNavigationBarItem(icon: Icon(Icons.home), label: 'first'),
            BottomNavigationBarItem(icon: Icon(Icons.home), label: 'second')
          ],
          currentIndex: view.state.index,
          onTap: (int index){
            // watchで取ってきたステート(viewのstate)にタップされた引数(index)番目のViewTypeを代入する
            view.state = ViewType.values[index];
            },
        ),
      ),
    );
  }

}

参考サイト

下記サイトが非常に参考になったのでこちらも合わせて見てみてください。

【Flutter】RiverpodでBottomNavigationBar

最後に

今回はRiverpodの使い方把握のためシンプルな実装にしています。
さらに詳しく実装したやり方についてもいずれ解説できればと思います。

不明点やおかしな点があればぜひコメントの方よろしくお願いします。

ではまた。

コメント

タイトルとURLをコピーしました