【Flutter】Navigatorを利用したシンプルな画面遷移プロジェクトのテンプレート

6 min read

一画面で完結するようなアプリを一つにまとめたいと思い、

Navigatorを利用したシンプルなテンプレートプロジェクトを作成しました。

できるだけ、簡単に適宜追加していける形となるようにしました。

【Flutter】各アプリへのシンプルな画面遷移テンプレート

完成テンプレート

構成

  • libディレクトリ以下の構成
    • appsディレクトリ
      • sample_appディレクトリ:個別アプリを格納
        • counter.dart:個別アプリのコード
    • screensディレクトリ
      • home_screen.dart:アプリをListViewで一覧表示するホーム画面
    • widgetsディレクトリ
      • app_button.dart:ホーム画面で表示するボタン
    • main.dart
    • routes.dart:画面遷移を行う準備ファイル

コード内容

  • main.dart
    • 細かい追加方法のメモを記載
    • MaterialApp内でRoute情報を記載(routes.dartを利用する)
/// ①アプリのコード配置
// appsディレクトリ下にsimple_app等ディレクトリを作成
// 元々のmain.dartをcounter.dart等にファイル名変更+「void main() => runApp(MyApp());」等は削除
// 各アプリは重複も発生してしまうが、個別ディレクトリ内のみで完結

/// ②アプリの遷移先追加方法
/// 1.ナビゲーション用の固有名追加[routes.dart]
/// 2.ナビゲーション用の遷移追加[routes.dart]
/// 3.遷移するためのボタンを追加[home_screen.dart]

import 'package:flutter/material.dart';

import 'routes.dart';
import 'screens/home_screen.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      onGenerateTitle: (context) => 'Apps',

      /// デバッグの際は以下をhomeScreen→○○に変更すればよい
      initialRoute: RouteGenerator.homeScreen, // routes.dart依存
      onGenerateRoute: RouteGenerator.generateRoute, // routes.dart依存
      home: HomeScreen(),
    );
  }
}
  • routes.dart
    • 何か新しく追加する場合
      • static const String xxx= '/xxx';とcase文case xxx:の部分を追加
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'apps/simple_app/counter.dart';
import 'screens/home_screen.dart';

class RouteGenerator {
  static const String homeScreen = '/';

  /// 1.ナビゲーション用の固有名追加
  static const String counter = '/counter';

  RouteGenerator._() {}

  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {

      /// 2.ナビゲーション用の遷移追加
      case homeScreen:
        return MaterialPageRoute(
          builder: (_) => const HomeScreen(),
        );
      case counter:
        return MaterialPageRoute(
          builder: (_) => const Counter(),
        );
      // 該当しない場合エラー
      default:
        throw RouteException('Route not found');
    }
  }
}

class RouteException implements Exception {
  final String message;
  const RouteException(this.message);
}
  • home_screen.dart
    • 何か新しく追加する場合
      • AppButtonウィジェットを追加
import 'package:flutter/material.dart';

import '../routes.dart';
import '../widgets/app_button.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen();

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ListView(
          children: <Widget>[
            /// 3.遷移するためのボタンを追加
            AppButton(
              pushName: RouteGenerator.counter,
              buttonText: 'Counter',
            ),
          ],
        ),
      ),
    );
  }
}
  • app_button.dart
    • ホーム画面に表示する各アプリへ遷移するための、シンプルなボタン
      • 押されると、Navigator.of(context)?.pushNamed()を実施
import 'package:flutter/material.dart';

class AppButton extends StatelessWidget {
  final String pushName;
  final String buttonText;
  const AppButton({this.pushName, this.buttonText});

  
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        Navigator.of(context)?.pushNamed(pushName);
      },
      child: Text(buttonText),
    );
  }
}
  • counter.dart
    • サンプルのカウントアップ(DartPad > Counter app in Flutter)アプリのコードを例として記載
      • void main() => runApp(MyApp());を削除し、MyAppのクラス名をCounterへ変更
// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:flutter/material.dart';

class Counter extends StatelessWidget {
  const Counter();

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

実行結果