【Flutter】画面遷移の基本/値の受け渡し

Flutter

Flutterでの基本的な画面遷移の方法(Navigator 1.0)と、画面遷移時に値を受け渡す方法について解説します。

スポンサーリンク

画面遷移の基本「Navigator」

NavigatorはFlutterの画面遷移用ウィジェットです。

画面遷移はpushで、遷移先のウィジェットを指定する方法と、名前で指定する方法の2種類があります。

  • Navigator.of(context).push()
  • Navigator.of(context).pushNamed()

画面遷移から戻るのはpopです。

  • Navigator.pop()

ウィジェットを指定して画面遷移

MaterialPageRoutebuilderで遷移先のウィジェットを指定して画面遷移します。

Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => NextPage(title: 'Next Page'),
  ),
);

名前をつけて画面遷移

名前付きで画面遷移する場合は、名前付きのルートを設定します。(デフォルトのカウンターアプリのコードで説明)

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // ホームは使わないのでコメントアウト
      // home: const MyHomePage(title: 'Flutter Demo'),
      // ここでページのルートを設定 --->
      initialRoute: '/',
      routes: <String, WidgetBuilder>{
        '/': (BuildContext context) =>
            const MyHomePage(title: 'Home Page'),
        '/next': (BuildContext context) =>
            const NextPage(title: 'Next Page'),
      },// <--- ここまで
    );
  }
}

initialRoute:はデフォルトで表示されるページなので、一番最初に表示させるページを指定しておきます。そして、routes:に名前付きページを設定します。

画面遷移は、上で設定したルート名を指定します。

Navigator.of(context).pushNamed('/next');

遷移先から戻る

画面遷移先から戻る場合はpop()を使います。

Navigator.pop(context);

これで遷移元の画面に戻ります。

値の受け渡し

値の受け渡しは、Navigatorargumentsプロパティを使用します。

  • Navigator.of(context).push()の場合
// 例としてargumentsにカウンターの値を設定しています
RouteSettings settings = RouteSettings(arguments: _counter);
// 戻り値を受ける場合はawaitで呼び出す(戻り値が無ければ不要)
var result = await Navigator.of(context).push(
  MaterialPageRoute(
    settings: settings,
    builder: (context) => NextPage(title: 'Next'),
  ),
);
  • Navigator.of(context).pushNamed()の場合
// 例としてargumentsにカウンターの値を設定しています
var args = _counter;
// 戻り値を受ける場合はawaitで呼び出す(戻り値が無ければ不要)
var result = await Navigator.of(context)
  .pushNamed('/next', arguments: args);

遷移先での値の受け取り

遷移先でargumentsの値を受け取るにはcontextが必要なので、遷移先ウィジェットのbuild以降で次のコードを呼び出します。

Object? args = ModalRoute.of(context)!.settings.arguments;

argumentsはObject型なので、String、int、カスタムクラスなど任意のObjectを受け渡し可能です。使用する際は、as intなどで型を指定してください。

遷移先からの戻り値

popの二番目の引数がresult値なので、ここに遷移元に引き渡す値を指定できます。

Navigator.pop(context, _counter);

※遷移元でこの戻り値を受け取る場合は、先の呼び出しの例に記載した通り、awaitでNavigator.push()/pushNamed()を呼び出してください。

サンプルコード

画面遷移のサンプルコードです。画面遷移元と遷移先の2つのカウンターページで相互にカウント値の受け渡しをしています。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      //homeは使わないのでコメントアウト
      //home: const MyHomePage(title: 'Flutter Demo Home Page'),
      // ここでページのルートを設定 --->
      // ※ページのルート名は各ページのクラスにstatic routeName='hoge'で設定しています
      initialRoute: MyHomePage.routeName,
      routes: <String, WidgetBuilder>{
        MyHomePage.routeName: (BuildContext context) =>
            const MyHomePage(title: 'Home Page'),
        NextPage.routeName: (BuildContext context) =>
            const NextPage(title: 'Next Page'),
      }, // <--- ここまで
    );
  }
}

class MyHomePage extends StatefulWidget {
  static const routeName = '/';

  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
            // 画面遷移ボタン ---
            ElevatedButton(
              onPressed: () async {
                RouteSettings settings = RouteSettings(arguments: _counter);
                var result = await Navigator.of(context).push(
                  MaterialPageRoute(
                    settings: settings,
                    builder: (context) => NextPage(title: 'Next'),
                  ),
                );
                setState(() {
                  _counter = result as int;
                });
              },
              child: const Text('Next Page'),
            ),
            Divider(),
            ElevatedButton(
              onPressed: () async {
                var args = _counter;
                var result = await Navigator.of(context)
                    .pushNamed('/next', arguments: args);
                setState(() {
                  _counter = result as int;
                });
              },
              child: const Text('Next Page (Named)'),
            ),
            // --- ここまで
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

// Nextページ
class NextPage extends StatefulWidget {
  static const routeName = '/next';

  const NextPage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  State<NextPage> createState() => _NextPageState();
}

class _NextPageState extends State<NextPage> {
  int _counter = 0;
  Object? args; //argsの受け取り用

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

  @override
  Widget build(BuildContext context) {
    // argumentsを受け取る --->
    // ※setStateの度にbuildが呼ばれるので初回(asrgがnull)の時だけ受け取る
    if (args == null) {
      args = ModalRoute.of(context)!.settings.arguments;
      _counter = args as int; //Object型なので型を指定する
    }
    // <--- ここまで

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
            // 画面遷移ボタン --->
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context, _counter);
              },
              child: const Text(
                'Home Page',
              ),
            ),
            // <--- ここまで
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

コメント

タイトルとURLをコピーしました