リファレンス
Reference

ルーティングを定義する

URLをコピーする Twitterでシェアする Facebookでシェアする

Navigator を使って、ページ遷移を実装します。

シンプルなページ遷移

まずは、もっともシンプルなページ遷移方法、1 ページ目から 2 ページ目へと遷移する方法を見てみましょう。

ここでは、 1 ページ目の中央にある「次のページに進む」ボタンを押すと、2 ページ目へと遷移する方法を例として使います。

まずは、独立した 2 枚のページを用意するために、 FirstPage と SecondPage という Widget クラスを作ります。

そして、 1 枚目のページに実装した ElevatedButton のプロパティ onPressed に、このボタンが押されたときに発動される Navigator を使ったイベントを書きます。

次のページに進むメソッドとして、 Navigatorpush メソッドを使います。

Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => NewPage()));

全体のコードは以下のようになります。

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text('1 ページ目')
      ),
      body: Center(
        child: ElevatedButton(
          child: Text(
            '次のページに進む',
          ),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondPage()),
            );
          },
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text('2 ページ目')
      ),
      body: Container(
        color: Colors.teal,
      ),
    );
  }
}

自動的に生成される Back ボタン

Flutterでは、遷移先ページの AppBar 左側に 、前ページに戻る Back ボタンが自動で生成されます。

こちらの Back ボタンは、AppBarleading プロパティで編集することができます。

以下のコードの例では、デフォルトで設定される Back ボタンのアイコンを左矢印のものに置き換えるコード例となります。

appBar: AppBar(
  leading: IconButton(
    icon: Icon(
      Icons.arrow_back,
      color: Colors.white,
    ),
    onPressed: () => Navigator.pop(context),
  ),
  title: Text('わかりやすい'),
),

変更を加えた後の、 Back ボタンは以下の画像のようになります。この方法を使って、オリジナリティを出すことができます。

前のページに戻る

Navigatorpop メソッドは、前のページへ戻る遷移を行ってくれます。

先ほどの Back ボタンのアイコンを変えるコード例でも使われていました。

Center(
  child: ElevatedButton(
    child: Text(
      '前のページに戻る',
    ),
    onPressed: () {
      Navigator.pop(context);
    },
  ),
),

スタックで考える push と pop の動き

Flutter の Navigator を使ったページ遷移は、スタックと呼ばれるデータ構造に基づいています。

ここで、積木をイメージしてみましょう。

積木は、順番に上へと積み重ねていく遊び道具です。

同じように、Flutter の Navigator も、新しいページへ遷移するときに上へ積み重ねていきます( push )。

反対に、積木を片付けるときは順番に上から取り除いていきます。

同じように、前のページへ遷移するときには、一番上に積み重なった現在見えているページを取り除きます( pop )。

そのイメージを持てば、ページ遷移の流れをより理解できると思います。

ページに名前を付けて、管理する

モバイルアプリでは、たくさんの画面遷移のルートを処理する必要が出てくることが多いです。

これらの無数のルートに名前を付けて管理すると、とても楽になります。

ルートに名前をつける際には、ディレクトリ構造で使用される / を使用することが慣習となっています。

アプリのホーム画面が / (ルートディレクトリ)とデフォルトで決まっているため、他のルートは /first/second/third のように名付けるようにしましょう。

以下の例では、押されるボタンに応じて異なる画面遷移が行われるアプリを紹介します。

まず、 MaterialApp の 引数に routes を指定していきます。

今回の例では、 '/blue' というルートに対して BluePage'/red' というルートに対して RedPage'/green' というルートに対して GreenPage 、を設定します。

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter リファレンス',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      initialRoute: '/',
      routes: <String, WidgetBuilder>{
        '/': (context) => MyHomePage(),
        '/blue': (context) => BluePage(),
        '/red': (context) => RedPage(),
        '/green': (context) => GreenPage(),
      },
    );
  }
}

上記のように initialRoute プロパティを使用する場合、 home プロパティを定義してはいけません。

続いてページ遷移です。

Navigator.of(context).pushNamed('/red')

とすることで、 '/blue' に対する、 BluePage へとページ遷移することが実現できます。

Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    ElevatedButton(
      child: Text(
        '青の間に進む',
      ),
      onPressed: () {
        Navigator.pushNamed(context, '/blue');
      },
    ),
    ElevatedButton(
      style: ElevatedButton.styleFrom(
        backgroundcolor: Colors.red,
      ),
      child: Text(
        '赤の間に進む',
      ),
      onPressed: () {
        Navigator.pushNamed(context, '/red');
      },
    ),
    ElevatedButton(
      style: ElevatedButton.styleFrom(
        backgroundcolor: Colors.teal,
      ),
      child: Text(
        '緑の間に進む',
      ),
      onPressed: () {
        Navigator.pushNamed(context, '/green');
      },
    ),
  ],
),

ページ遷移の値渡し

例えば、First ページ から Second ページ へと遷移するときに、First ページ が持っている値を Second ページ でも使いたい場合はどうすればよいでしょうか。

以下の画像では、文字列「Flutter は楽しい」という値を、次のページに送り、次のページでも受け取れていることを表しています。

難しそうに思えるかもしれませんが、簡単に実装することができます。

Second ページ で受け取る値の準備をしてあげる。

値を受け取る Second ページの最初に、この SecondPage を作る際に必要な値を指定してあげます。

ここでは、受け取る引数の値のことを message という変数名にし、コンストラクタの中を {} で覆った「名前付き引数」と呼ばれる形にしています。

名前付き引数は、たくさんの値を渡す必要になったときに渡す順番を考える必要もなく、引数の名前ごとに渡したい値を当てはめていけばよいので大変便利です。

class SecondPage extends StatelessWidget {
  final String message;

  SecondPage({required this.message});

First ページから push する際に、渡したい値を指定する。

Navigatorpush メソッドを使って、First ページから Second ページ遷移する際に、 SecondPage が受け取る値 message に、文字列の変数 message を渡してあげます。

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => SecondPage(message: message),
  ),
);

全体のコードは以下のようになります。

class FirstPage extends StatelessWidget {
  final String message = 'Flutter は楽しい';  // 文字列 message を定義する

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('渡す値:「$message」'),
          ElevatedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => SecondPage(message: message),
                ),
              );
            },
            child: Text('次のページに値を渡す'),
          ),
        ],
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  final String message;

  SecondPage({required this.message});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('受け取った値'),
          Text(message),
        ],
      ),
    );
  }
}

参考リンク