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 1 year has passed since last update.

FlutterのPopupMenuButtonとPopupMenuItemを最大限利用してみた件

Posted at

PopupMenuButtonのベース実装

ベースとなる最もシンプルなポップアップメニューを作成しました
機能もデザインもシンプルです

popup_menu_button_screen.dart
class PopupMenuButtonScreen extends StatefulWidget {
  const PopupMenuButtonScreen({super.key});

  @override
  State<StatefulWidget> createState() => _PopupMenuButtonScreen();
}

class _PopupMenuButtonScreen extends State<PopupMenuButtonScreen> {
  String selectedValue = '月曜日';
  final lists = ['月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'];

  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        // Sting以外も指定できるよ
        child: PopupMenuButton<String>(
          child: Text(selectedValue),
          itemBuilder: (BuildContext context) {
            return lists.map((String list) {
              return PopupMenuItem(
                value: list,
                child: Text(list),
              );
            }).toList();
          },
          onSelected: (String list) {
            setState(() {
              selectedValue = list;
            });
          },
        ),
      ),
    );
  }
}

PopupMenuButtonの改修

DropdownButtonに比べて自由度が高かったのでPopupMenuButtonの方が扱いやすかったです
分かりにくい設定もほぼなかったので直感的に実装できるのも良かったです
ボタン自体のUIはchild配下で指定できるので他のwidgetとも親和性があっていいかと思います
個人的に一番好きなところは表示されるリストの位置を指定できるとこですね
DropdownButtonでもできるのかもしれないですがこっちの方が確実に楽に設定できます

強いてめんどくさい点を挙げるならiconとchildが一緒に使えないくらいですが、
ほぼ気にならないので問題ないかと思います
入力する系の実装が必要な場合はPopupMenuButtonは使えなそうなのでご注意を

詳しくは公式サイトをご覧ください
https://api.flutter.dev/flutter/material/PopupMenuButton-class.html

popup_menu_button_screen.dart
        child: PopupMenuButton<String>(
          itemBuilder: (BuildContext context) {
            return lists.map((String list) {
              return PopupMenuItem(
                value: list,
                // ポップアップリストをタップした際に行う処理
                onTap: () {
                  debugPrint('ポップアップリストをタップしたよ');
                },
                // falseにするとタップできなくなるよ
                enabled: true,
                // 最小値はkMinInteractiveDimensionで指定されているよ(min 48)
                height: 60,
                // ポップアップリストのpaddingを指定できるよ
                padding: EdgeInsets.zero,
                // ポップアップリストのTextStyleを指定できるよ
                textStyle: const TextStyle(color: Colors.red),
                // webでみた時にポップアップリストにフォーカスが当たって時の処理
                mouseCursor: MouseCursor.defer,
                child: Text(list),
              );
            }).toList();
          },
          onSelected: (String list) {
            setState(() {
              selectedValue = list;
            });
          },
          // 設定さている文字列がリストにあると強調して表示してくれるよ
          initialValue: selectedValue,
          // ポップアップリストを表示したけど何もせずに閉じた際に行う処理
          onCanceled: () {
            debugPrint('ポップアップリストを表示したけど何も選択しなかったよ!');
          },
          // 長押しした時に表示される文言だよ
          // webだとクリックした時に表示されるよ
          tooltip: '長押しされたよ',
          // 影を指定できるよ
          elevation: 0,
          // childではなくiconを使った時に反映されるよ
          padding: const EdgeInsets.all(30),
          // PopupMenuButtonをタップした時のエフェクトの半径を指定できるよ
          splashRadius: 100,
          // childとiconどちらかしか使えないよ
          // icon: const Icon(Icons.change_circle),
          // アイコンのサイズを指定できるよ
          // iconSize: 30,
          // ポップアップメニューを表示する位置を指定できるよ
          // childを始点にしているので注意
          offset: const Offset(10, 100),
          // falseにするとタップできなくなるよ
          enabled: true,
          // ポップアップメニューのレイアウトを指定できるよ
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10),
          ),
          // ポップアップメニューの色を指定できるよ
          color: Colors.yellow,
          // trueだとクリックサウンドを再生できたりするよ(Feedback class参照)
          enableFeedback: true,
          // ポップアップメニューのサイズを指定できるよ
          constraints: const BoxConstraints(
            minWidth: 4.0 * 56.0,
            maxWidth: 5.0 * 56.0,
          ),
          // ポップアップメニューが表示される位置を指定できるよ
          position: PopupMenuPosition.under,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                selectedValue,
              ),
            ],
          ),
        ),
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?