2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flutter - PopupMenuButtonでページ遷移機能を実装

2
Last updated at Posted at 2022-04-30

はじめに

FlutterでPopupMenuButtonを使ってページ遷移機能を実装します。
次図のように、PopupMenuButtonで選択することでページ画面を遷移させるようにします。

実装

  • lib配下のディレクトリ構成
    次図のような構成で実装しています。
    |-- lib
    |    |-- main.dart
    |    |-- app_home.dart
    |    |-- pages
    |          |-- page1.dart
    |          |-- page2.dart

  • lib/main.dart
    StatefulWidgetAppHomeを呼び出しているだけです。

import 'package:flutter/material.dart';
import 'package:app_1/app_home.dart'; // プロジェクト名はapp_1としています

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),

      // StatefulWidgetであるAppHomeの呼び出し
      home: const AppHome(title: 'Demo: Page Transition'),
    );
  }
}
  • lib/app_home.dart
    _AppStateクラスにおいて、PopupMenuButtonのクリック時の動作を定義するonSelectedを利用して_valueを切り替えています。
    具体的には、onSelectedに指定した_select関数でsetState関数を呼び出し、_valueを切り替えるとともに状態(State)をリビルドしています。(参考: Stateのライフサイクルについて
    これにより、Scaffoldbodyが切り替わります。
    また、PopupMenuButtonに付しているページのアイコンはこちらから選んでいます。
import 'package:flutter/material.dart';
import 'package:app_1/pages/page1.dart';
import 'package:app_1/pages/page2.dart';

// ページ情報(ページ番号、ページ名、アイコン)を定義するクラス
class MenuItem {
  int value;
  String name;
  IconData icon;
  MenuItem(
    this.value,
    this.name,
    this.icon
  );
}

// ページ情報のリストを定義
List<MenuItem> _list = <MenuItem>[
  MenuItem(1, 'Page 1', Icons.filter_1),
  MenuItem(2, 'Page 2', Icons.filter_2),
];

// AppHomeクラス(StatefulWidget)
class AppHome extends StatefulWidget {
  const AppHome({super.key, required this.title});
  final String title;

  @override
  State<AppHome> createState() => _AppState();
}

// _AppStateクラス(AppHomeの内部State)
class _AppState extends State<AppHome> {
  MenuItem _value = _list[0];
  bool favorite = false;
  void _select(MenuItem value) {
    // setStateを契機に状態がリビルドされる
    setState(() {
      _value = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
          actions: <Widget>[
            PopupMenuButton(
              initialValue: _value,
              icon: Icon(Icons.more_vert),
              enabled: true,
              // onSelectedで選択時の挙動を定義する
              onSelected: _select,
              itemBuilder: (context) {
                return _list.map((MenuItem choice) {
                  return PopupMenuItem(
                    value: choice,
                    child: ListTile(
                      leading: Icon(choice.icon),
                      title: Text(choice.name),
                    ),
                  );
                }).toList();
              }
            )
          ],
        ),
        body: PageWidget(),
      ),
    );
  }
  PageWidget() {
    if(_value.value == _list[0].value) {
      return Container(child: Page1(title: widget.title));
    }
    if(_value.value == _list[1].value) {
      return Container(child: Page2(title: widget.title));
    }
  }
}
  • lib/pages/page1.dart
    ページ1をStatelessWidgetで作成。
import 'package:flutter/material.dart';

class Page1 extends StatelessWidget {
  const Page1({super.key, required this.title});
  final String title;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: this.title,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        body: Center(
          child: Text(
            'Page 1',
            style: TextStyle(
              fontSize: 24,
              fontStyle: FontStyle.italic,
              color: Colors.blue,
            ),
            textAlign: TextAlign.center
          ),
        ),
      ),
    );
  }
}
  • lib/pages/page2.dart
    ページ2をStatelessWidgetで作成。
import 'package:flutter/material.dart';

class Page2 extends StatelessWidget {
  const Page2({super.key, required this.title});
  final String title;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: this.title,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        body: Center(
          child: Text(
            'Page 2',
            style: TextStyle(
              fontSize: 24,
              fontStyle: FontStyle.italic,
              color: Colors.red
            ),
            textAlign: TextAlign.center
          ),
        ),
      ),
    );
  }
}

動作環境

  • WSL2(Ubuntu20.04 LTS)
  • Flutter: 2.13.0
  • Dart: 2.18.0
  • DevTools: 2.12.2

おわりに

Flutterは社内ハッカソンに参加した際のデモに使用し、興味を持ちました。
今後も勉強していきたいと思っています。

参考文献

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?