中安拓也のブログ

プログラミングについて書くブログ

【Flutter】ルーティングライブラリFluroの使い方

はじめに

FlutterのルーティングライブラリであるFluroの使い方について、簡単なTODOアプリの実装を通して説明していきます。

環境

本記事のサンプルアプリで使用しているライブラリのバージョンです。

  • flutter: 2.8.1
  • fluro: 2.0.3

インストール

$ flutter pub add fluro

Fluroの使い方

まずはFluroを使ったルーティングの設定方法から説明していきます。

ルーティングの初期設定

Flutterのエントリーポイントであるmain()メソッド内で、ルーティングの初期設定を行なっています。

lib/main.dart

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

import 'router/routes.dart';

void main() {
  // FluroRouterオブジェクトの初期化
  final router = FluroRouter();
  // ルーディングの設定
  Routes.configureRoutes(router);
  // 他のWidgetからも呼び出せるようにFluroRouterオブジェクトをrouterプロパティに設定
  TodoApp.router = router;

  runApp(const TodoApp());
}

class TodoApp extends StatelessWidget {
  static FluroRouter? router;

  const TodoApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 最初のrouteを「/」に設定
    // Fluroから提供されているgeneratorをonGenerateRouteに設定
    return MaterialApp(
        initialRoute: '/', onGenerateRoute: TodoApp.router?.generator);
  }
}

main()メソッド内では、Fluroを使ってルーティングをするために必要なFluroRouter()オブジェクトの定義と、routeと画面の紐付けをするために作成したメソッドであるRoutes.configureRoutesを呼び出しています。

また、WidgetツリーのルートであるTodoAppのstaticプロパティrouterに、FluroRouterオブジェクトを設定することで、他画面でもFluroルーターにアクセスできるようにします。

  // FluroRouterオブジェクトの初期化
  final router = FluroRouter();
  // ルーディングの設定
  Routes.configureRoutes(router);
  // 他のWidgetからも呼び出せるようにFluroRouterオブジェクトをrouterプロパティに設定
  TodoApp.router = router;

以下では、MaterialAppのコンストラクタでinitialRoute: '/'と定義することで最初に遷移するrouteを「/」に設定しています。

また、onGenerateRoute: TodoApp.router?.generatorと定義することでルーティング設定をFlutter側に渡しています。

    // 最初のrouteを「/」に設定
    // Fluroから提供されているgeneratorをonGenerateRouteに設定
    return MaterialApp(
        initialRoute: '/', onGenerateRoute: TodoApp.router?.generator);
  }

routeと遷移先画面の紐付け

main()メソッドから呼んでいるRoutes.configureRoutesメソッドでrouteと遷移先画面の紐付けをしていきます。

lib/router/routes.dart

import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter_basic_todo/model/todo.dart';
import 'package:flutter_basic_todo/pages/account_page.dart';
import 'package:flutter_basic_todo/pages/add_todo_page.dart';
import 'package:flutter_basic_todo/pages/todo_detail_page.dart';
import 'package:flutter_basic_todo/pages/todo_list_page.dart';

// 遷移先に渡したい値がない時に使用するハンドラー
// 単に引数で設定した遷移先の画面を返すだけのハンドラーになっている
Handler createBasicHandler(Widget targetWidget) {
  return Handler(
      handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
    return targetWidget;
  });
}

// アカウント画面に遷移する時に呼び出されるハンドラー
// パスに設定したuserNameパラメーターを遷移先の画面に渡している
Handler accountPageHandler = Handler(
    handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
  return AccountPage(params['userName']!.first);
});

// TODO詳細画面に遷移する時に呼び出されるハンドラー
// Todoオブジェクトを遷移先の画面に渡している
Handler todoDetailPageHandler = Handler(
    handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
  final args = context?.settings?.arguments as Todo;
  return TodoDetailPage(args);
});

class Routes {
  // routeと遷移先の画面、遷移時に呼び出されるハンドラーを設定している
  static void configureRoutes(FluroRouter router) {
    router
      // 最初に遷移する画面、route: '/'でTODOリスト画面に遷移する
      ..define('/', handler: createBasicHandler(const TodoListPage()))
      // route: '/add'でTODO追加画面に遷移するように設定している
      ..define('/add', handler: createBasicHandler(const AddTodoPage()))
      // route: '/account/:userName'でアカウント画面に遷移する
      // ':userName'パラメーターでユーザー名を遷移先の画面に渡している
      ..define('/account/:userName', handler: accountPageHandler)
      // route: '/detail'でTODO詳細画面に遷移する
      // Todoオブジェクトを遷移先の画面に渡している
      ..define('/detail', handler: todoDetailPageHandler);
  }
}

Fluroではルーティングの設定を、routeとハンドラー関数をマッピングする形式で実施します。 例えば、..define('/detail', handler: todoDetailPageHandler)では、画面遷移時に/detailがrouteとして指定された時には、ハンドラー関数としてtodoDetailPageHandlerを呼び出す、という感じです。

上記のRoutes.configureRoutesメソッドで実施しているルーディングの設定とそのルーティングを使った画面遷移の方法について詳しく説明していきます。

値を渡さない場合の画面遷移

まず、以下のルーディング設定では、route/addに合致した場合にハンドラーcreateBasicHandler(const AddTodoPage())を呼ぶ、という設定をしています。

createBasicHandler()では、引数として渡されたWidgetをそのまま返すという処理を行なっているため、route/addに合致するとTODO追加画面(AddTodoPage)に遷移します。

// 遷移先に渡したい値がない時に使用するハンドラー
// 単に引数で設定した遷移先の画面を返すだけのハンドラーになっている
Handler createBasicHandler(Widget targetWidget) {
  return Handler(
      handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
    return targetWidget;
  });
}

class Routes {
  static void configureRoutes(FluroRouter router) {
    router
      // route: '/add'でTodo追加画面に遷移するように設定している
      ..define('/add', handler: createBasicHandler(const AddTodoPage()))
  }

上記のルーティング設定を使用して画面遷移を実施する場合は以下のようになります。

// TODO追加画面に遷移する
TodoApp.router?.navigateTo(context, '/add',
              transition: TransitionType.material);

上記のFluroのFluroRouter.navigateToメソッドはFlutterのNavigator.pushを拡張したものなので基本的な使い方はNavigator.pushと同じになります。

例えば、TODO追加画面から遷移元の画面に戻した値を受け取るときは、FlutterのNavigatorを使用した場合と同様に以下の書き方になります。

// TODO追加画面
// 遷移元の画面に値('send value')を渡す
TodoApp.router?.pop(context, 'send value');
// 遷移元の画面
// 遷移先から戻る時に渡された値('send value')を受けとる
final newListText = await TodoApp.router?.navigateTo(context, '/add',
              transition: TransitionType.material);

なお、遷移元の画面に戻る時に使用するFluroRouter.pop()は、裏側でFlutterのNavigator.pop()を呼んでいるだけなので、両者に違いはありません。

パラメーター付きrouteで遷移先画面に値を渡す
// アカウント画面に遷移する時に呼び出されるハンドラー
// パスに設定したuserNameパラメーターを遷移先の画面に渡している
Handler accountPageHandler = Handler(
    handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
  return AccountPage(params['userName']!.first);
});

class Routes {
  static void configureRoutes(FluroRouter router) {
    router
      // route: '/account/:userName'でアカウント画面に遷移する
      // ':userName'パラメーターでユーザー名を遷移先の画面に渡している
      ..define('/account/:userName', handler: accountPageHandler)
  }
  }
}

上記のルーティング設定は、route/account/[渡したい値]に合致した場合にハンドラーaccountPageHandlerを呼び出して、アカウント画面(AccountPage)にrouteに含めたパラメーターを渡して遷移する、という設定になります。

上記のルーティング設定を使用して画面遷移を実施する場合は以下のようになります。

const accountName = '花籠総矢';
// アカウント画面に遷移する
TodoApp.router?.navigateTo(context, '/account/$accountName');

上記のように画面遷移することで、遷移先の画面に値'花籠総矢'を渡すことができます。

オブジェクトを遷移先の画面に渡す

パラメーター付きrouteを使う方法以外にも、BuildContext.settings.arguments経由で値を渡す方法もあります。

以下のルーティング設定では、route/detailに合致した場合にTodoオブジェクトをTODO詳細画面(TodoDetailPage)に渡す設定をしています。

// Todo詳細画面に遷移する時に呼び出されるハンドラー
// Todoオブジェクトを遷移先の画面に渡している
Handler todoDetailPageHandler = Handler(
    handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
  final args = context?.settings?.arguments as Todo;
  return TodoDetailPage(args);
});

class Routes {
  static void configureRoutes(FluroRouter router) {
    router
      // route: '/detail'でTodo詳細画面に遷移する
      // Todoオブジェクトを遷移先の画面に渡している
      ..define('/detail', handler: todoDetailPageHandler);
  }

上記のルーティング設定を使用して画面遷移を実施する場合は以下のようになります。

          TodoApp.router?.navigateTo(
            context,
            '/detail',
            routeSettings: RouteSettings(
              arguments: Todo('todo-101', 'ゴミ出し'),
            ),
          );

上記の画面遷移では、遷移先の画面(TodoDetailPage)にTodo('todo-101', 'ゴミ出し')を渡しています。

参考サイト

fluro | Flutter Package