go_routerのGoRouterクラスにはredirectという関数があります。こちらの関数はナビゲーションイベントが発生する毎に発火し、条件にあった画面にリダイレクトさせることができます。
class GoRouterSample extends StatelessWidget {
...
late final _router = GoRouter(
redirect: (state) {
// ここにリダイレクト先と条件を書いていく
},
);
}
今回はこのredirectを利用してwebページによくあるような「○秒後にリダイレクト」を表現してみました。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F2466417%2F820ad699-bbb6-3f1a-8377-bed13b7fafad.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=08120bd91a6ff95ae3e401f825459b05)
実装内容
秒数を管理するクラスを定義(ValueNotifier便利だな〜)
class Count extends ValueNotifier<int> {
Count(super.value);
void countDown() {
value = value - 1;
}
void resetCount() {
value = 5;
}
}
main.dartにgo_routerの諸々を定義。アプリ起動時にget_itというパッケージでCountクラスをシングルトンとして登録しています。
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// get_itを使用してCountクラスをシングルトンとして登録
GetIt.I.registerSingleton(Count(5));
runApp(
GoRouterSample(),
);
}
class GoRouterSample extends StatelessWidget {
GoRouterSample({Key? key}) : super(key: key);
// get_itに登録したCountクラスを取得
final countRepository = GetIt.I<Count>();
@override
Widget build(BuildContext context) => MaterialApp.router(
routeInformationProvider: _router.routeInformationProvider,
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate,
);
late final _router = GoRouter(
initialLocation: '/login',
// ルート診断情報の出力を有効にする(なくても良い)
debugLogDiagnostics: true,
// Listenableクラスに変化があればルートがリフレッシュされる(redirectが発火する)
refreshListenable: countRepository,
routes: [
GoRoute(
path: '/login',
builder: (context, state) => TopPage(),
),
GoRoute(
path: '/first',
builder: (context, state) => FirstLoginPage(),
),
GoRoute(
path: '/home',
builder: (context, state) => HomePage(),
),
],
// ナビゲーションイベントが起こるたびに発火
redirect: (state) {
// countが0になったらcountをリセットし、ホーム画面にリダイレクト
// (countを0にしないと無限ループしてしまうため)
if (countRepository.value == 0) {
countRepository.resetCount();
return '/home';
}
// nullを返すと本来の遷移先に遷移してくれる
return null;
},
);
}
GoRouterコンストラクタのrefreshListenableプロパティに監視したいクラスを指定します(ChangeNotifierやValueNotifer等)。指定したクラス(正しくは状態変数?)に変更があった場合はルートをリフレッシュしてくれます(つまりredirectを発火してくれる)
今回はこれを活用しValueNotifier継承クラスでint型の秒数を管理。1秒ごとに-1して状態変数を更新。ValueNotifier継承クラスが更新されたためredirectが発火され、もし秒数が0の場合はホーム画面にリダイレクト。といった形で実装しています。
FirstLoginPageではTimer
を使用して1秒ごとに状態変数を-1するように実装しています。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_playground/presentasion/pages/playground/go_router/main.dart';
import 'package:get_it/get_it.dart';
class FirstLoginPage extends StatefulWidget {
const FirstLoginPage({Key? key}) : super(key: key);
@override
State<FirstLoginPage> createState() => _FirstLoginPageState();
}
class _FirstLoginPageState extends State<FirstLoginPage> {
// 登録済みのCountクラスを取得
final count = GetIt.I<Count>();
late Timer _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(
const Duration(seconds: 1),
(Timer timer) {
// 1秒ごとにcount.valueを-1している
count.countDown();
setState(() {});
},
);
}
@override
void dispose() {
super.dispose();
_timer.cancel();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('初回ログイン'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
child: Text(
count.value.toString(),
),
),
const Text('秒後にホーム画面に遷移します。'),
],
),
],
),
),
);
}
}
(TopPageとHomePageは特段解説する必要はないと思うので省きます。)
今回は解説というよりは「こんなもの作ってみました〜」という感じなので具体的な説明は省きましたが、go_routerでリダイレクトができるってことは伝わったかなと思います。どなたかの参考になれば嬉しいです。
参考