Flutter hooks_reverpod Navigator2.0で画面遷移する
みなさんこんにちは
今日のお題
Flutter + hooks_reverpod + Navigator 2.0で画面遷移を行いたい。
とゆうのも、これからアプリを作るのであれば、なにかしらのボタンを押したら、コンフィグ画面なりに移動したり戻ったりができた方がいい。のではないかと考えて。
Navigator2.0の今んとこの理解
ちょっとややこしいのですが、1.0もあってマイナーチェンジなのかと思いや、結構大きく変わっているようです。
Navigator1.0:HTMLのa hrefのリンクのような感じ。ボタンを押したら、あらかじめ設定されているページに移動する。
Navigator2.0:スマホのプッシュ通知を、スマホ内で完結しているイメージ。アプリのボタンなりデーモンなりが、特定の変数を監視していて、監視している、特定の変数に変更があった場合に、変更に応じてあらかじめ設定してあるページに移動する。
※ページにいどうだけではなくて、色々出来る。画像を変更したり。
ソース
とりあえず、Githubにアップロードしておきました。
main.dart
ここに、監視変数が分かった時の処理を書く。
そのうちソースを分離したいですね。
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'entity/data.dart';
import 'view/myhome.dart';
import 'view/page2.dart';
//ここが一番最初に動く
void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
//class MyApp extends StatelessWidget {
class MyApp extends HookConsumerWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
//Widget build(BuildContext context) {
int intPageID = ref.watch(kousinProvider);
//return const MaterialApp(
return MaterialApp(
//home: MyHomePage(),
home: Navigator(//Navigator2.0の登録
pages: [
const MaterialPage(//初期起動ページ設定
key: ValueKey('ListPage'),
child: MyHomePage(),
),
if (intPageID == 1)
const MaterialPage(
key: ValueKey('ListPage2'),
child: Page2Page(),
),
],
onPopPage: (route, result) {//Navigator2.0これも必須
if (!route.didPop(result)) {
return false;
}
ref.read(kousinProvider.state).state = 0;
return true;
},
),
);
}
}
myhome.dart
ref.read(kousinProvider.notifier).update((state) => 1);
↑の行で共通変数の数値を変えて、main.dartのpages: に記載されている、配列の(この場合は、1※0スタートです。)場所の処理を行う。
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../entity/data.dart';
class MyHomePage extends HookConsumerWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
//今回追加
final ButtonStyle style = ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20));
return Scaffold(
appBar: AppBar(
title: const Text('Riverpod counter example'),
),
body: Center(
/* //元々あったソース
child: Text(
'$count',
style: Theme.of(context).textTheme.headline4,
),
*/
//今回追加
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'$count',
style: Theme.of(context).textTheme.headline4,
),
const SizedBox(height: 30),
ElevatedButton(
style: style,
//onPressed: () {},//ボタン押した時に動く。今は何も入れていない。
onPressed: () {
ref.read(counterProvider.notifier).setIncrement(0);
},
child: const Text('Enabled'),
),
ElevatedButton(
onPressed: () {
print("### MyHomePage#Widget onPressed2 !");
ref.read(kousinProvider.notifier).update((state) => 1);//ここで共通変数更新→ページ切り替え
/*
//Navigator1.0
Navigator.of(context).push<void>(
MaterialPageRoute(
builder: (context) => const MySecondPage(),
),
);
*/
},
child: const Text(
"画面移動",
style: TextStyle(
color: Colors.white,
),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: const Icon(Icons.add),
),
);
}
}
page2.dart
ページ移動先が必要なので、新たに新設。
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../entity/data.dart';
//このソースは、ページ遷移を確認するために新規に作成
class Page2Page extends HookConsumerWidget {
const Page2Page({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: const Text('Riverpod Navigator2 example'),
),
body: Center(
child: Column(
children: <Widget>[
ElevatedButton(
onPressed: () {
print("### NewWindowPage#Widget onPressed3 !");
ref.read(kousinProvider.notifier).update((state) => 0);//ここで共通変数更新→ページ切り替え
/*
//Navigator1.0
Navigator.of(context).push<void>(
MaterialPageRoute(
builder: (context) => const MySecondPage(),
),
);
*/
},
child: const Text(
"戻る",
style: TextStyle(
color: Colors.white,
),
),
),
]
),
),
);
}
}
data.dart
ページ切り替えようの共通変数の定義と、データの上書きができるように処理の追加。
実際に監視しているのは、main.dartの以下の部分。
int intPageID = ref.watch(kousinProvider);
//hooks_riverpodを利用するための宣言
import 'package:hooks_riverpod/hooks_riverpod.dart';
//Providerの宣言
final counterProvider = StateNotifierProvider<Counter, int>((_) => Counter());
//Providerに紐づいたクラスと関数
class Counter extends StateNotifier<int> {
Counter() : super(0);//stateを0で初期化
//increment()関数が呼ばれたら、stateの数字を+1する。
void increment() => state++;
//カウンターの値が指定値に変更出来る関数を作る
void setIncrement( int intData ){
state = intData;
}
}
//ページを切り替えるための共通変数//Navigator2.0の状態変数
final kousinProvider = StateProvider((ref) => 0);
class Kousin {
static void update(int intPageID) {
// kousinProviderを更新する
StateProvider((ref) {
ref.read(kousinProvider.notifier).state = intPageID;
});
}//static void update
}
ファイル構成
※関係ないですが、MACのこの切り抜き機能とってもいいですね。Windowsにもあるのかもしれないけど。
動作確認
無事に画面遷移できました。当然、TOP画面にも戻れますよ。
今日の課題
意外にNavigator2.0の仕組みに悩みました。ネットで色々当たったのですが、いまいち完コピで動くようなものが発見できず、というのが続きました。
なんというか、Navigato1.0で大体のケースは吸収できているので、わざわざNavigator2.0にする必要ないってのもあるんだと思います。というのが、情報が少ない理由なんですかね。
しかも面倒でも、大体のことは、Navigator1.0でもできるらしいですしね。
今後の予定
説明のために、旧コードとかを残しつつ、最低限必要な機能が揃ったので、具体的に何か作っていきたいなと。
あーでも、Google Mapとか見れると面白そうですね。
Discussion