【Flutter】go_routerでページを離れる際にダイアログを出す

2023/09/19に公開

1.はじめに

go_routerのGoRouteクラスにonExitコールバックが実装されました。
これにより、ページを離れる際に警告のアラートを表示するようなことができるようになりました。ありがたいです。

https://github.com/flutter/packages/commit/0023d01996576e494094793a6552463f01c5627a

バージョンは、go_router: ^10.2.0 です。
https://pub.dev/packages/go_router/changelog#1020

元となっているissueはこちらです。
https://github.com/flutter/flutter/issues/102408

ドキュメントにもこのように記載があるように、WillPopScopeとの互換性が無いということで困っていました。
https://pub.dev/documentation/go_router/latest/topics/Navigation-topic.html

2.サンプル

以下のように、ページを離れる際にonExitで検知することができます。
Webのブラウザバックでもダイアログを表示することができました。

サンプルコードです。

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

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

final GoRouter _router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'details',
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
          onExit: (BuildContext context) async {
            final bool? confirmed = await showDialog<bool>(
              context: context,
              builder: (_) {
                return AlertDialog(
                  content: const Text('Are you sure to leave this page?'),
                  actions: <Widget>[
                    TextButton(
                      onPressed: () => Navigator.of(context).pop(false),
                      child: const Text('Cancel'),
                    ),
                    TextButton(
                      onPressed: () => Navigator.of(context).pop(true),
                      child: const Text('Confirm'),
                    ),
                  ],
                );
              },
            );
            return confirmed ?? false;
          },
        ),
      ],
    ),
  ],
);

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home Screen')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => context.go('/details'),
          child: const Text('Go to the Details screen'),
        ),
      ),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Details Screen')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => context.go('/'),
          child: const Text('Go back to the Home screen'),
        ),
      ),
    );
  }
}

3.おわりに

本件は、先月辺りにIssueプライオリティがP3からP1へ変わっていたので、近々修正されそうだなと思って通知をsubscribeしていました。

ありがたや。

Discussion