【问题标题】:Easiest way to add 3 dot pop up menu AppBar in Flutter在 Flutter 中添加 3 点弹出菜单 AppBar 的最简单方法
【发布时间】:2019-09-28 09:17:27
【问题描述】:
  1. 我想在我的应用的应用栏中添加一个 3 点弹出菜单按钮

  2. 它必须是可点击的[导航到其他小部件、页面]

  3. 请告诉如何以更简单的方式添加弹出菜单按钮

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    最简单的方法无疑是避免使用辅助类。 从 Dart 2.2 开始,使用 set literals,我们可以直接将菜单项的映射放在应用栏中

     appBar: AppBar(
            title: Text('Homepage'),
            actions: <Widget>[
              PopupMenuButton<String>(
                onSelected: handleClick,
                itemBuilder: (BuildContext context) {
                  return {'Logout', 'Settings'}.map((String choice) {
                    return PopupMenuItem<String>(
                      value: choice,
                      child: Text(choice),
                    );
                  }).toList();
                },
              ),
            ],
          ),
    

    并在方法中使用项目文本的值处理点击

    void handleClick(String value) {
        switch (value) {
          case 'Logout':
            break;
          case 'Settings':
            break;
        }
    }
    

    【讨论】:

    • 这样三个点就会显示在一个堆栈中,您可以使用 RotateBox 进行包装。 EJ: RotatedBox( QuarterTurns: 1, child: PopupMenuButton(...) )
    • 关于RotatedBox - 非常有帮助,谢谢。在到目前为止的测试中,我发现它只对 iOS 是必需的。
    • @Ondrej 如果某些菜单选项有一些子菜单选项,如何使用它?
    • @ManuelOrtiz 或者您可以将图标添加到PopupMenuButton,例如:icon: const Icon(Icons.more_vert_rounded),。这是跨平台的。
    【解决方案2】:

    你可以使用 Flutter 文档中的这个例子:

    https://flutter.dev/docs/catalog/samples/basic-app-bar

    
    // Copyright 2017 The Chromium Authors. 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';
    
    // This app is a stateful, it tracks the user's current choice.
    class BasicAppBarSample extends StatefulWidget {
      @override
      _BasicAppBarSampleState createState() => _BasicAppBarSampleState();
    }
    
    class _BasicAppBarSampleState extends State<BasicAppBarSample> {
      Choice _selectedChoice = choices[0]; // The app's "state".
    
      void _select(Choice choice) {
        // Causes the app to rebuild with the new _selectedChoice.
        setState(() {
          _selectedChoice = choice;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Basic AppBar'),
              actions: <Widget>[
                // action button
                IconButton(
                  icon: Icon(choices[0].icon),
                  onPressed: () {
                    _select(choices[0]);
                  },
                ),
                // action button
                IconButton(
                  icon: Icon(choices[1].icon),
                  onPressed: () {
                    _select(choices[1]);
                  },
                ),
                // overflow menu
                PopupMenuButton<Choice>(
                  onSelected: _select,
                  itemBuilder: (BuildContext context) {
                    return choices.skip(2).map((Choice choice) {
                      return PopupMenuItem<Choice>(
                        value: choice,
                        child: Text(choice.title),
                      );
                    }).toList();
                  },
                ),
              ],
            ),
            body: Padding(
              padding: const EdgeInsets.all(16.0),
              child: ChoiceCard(choice: _selectedChoice),
            ),
          ),
        );
      }
    }
    
    class Choice {
      const Choice({this.title, this.icon});
    
      final String title;
      final IconData icon;
    }
    
    const List<Choice> choices = const <Choice>[
      const Choice(title: 'Car', icon: Icons.directions_car),
      const Choice(title: 'Bicycle', icon: Icons.directions_bike),
      const Choice(title: 'Boat', icon: Icons.directions_boat),
      const Choice(title: 'Bus', icon: Icons.directions_bus),
      const Choice(title: 'Train', icon: Icons.directions_railway),
      const Choice(title: 'Walk', icon: Icons.directions_walk),
    ];
    
    class ChoiceCard extends StatelessWidget {
      const ChoiceCard({Key key, this.choice}) : super(key: key);
    
      final Choice choice;
    
      @override
      Widget build(BuildContext context) {
        final TextStyle textStyle = Theme.of(context).textTheme.display1;
        return Card(
          color: Colors.white,
          child: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Icon(choice.icon, size: 128.0, color: textStyle.color),
                Text(choice.title, style: textStyle),
              ],
            ),
          ),
        );
      }
    }
    
    void main() {
      runApp(BasicAppBarSample());
    }
    
    

    【讨论】:

    • 我很好奇。这是唯一的方法吗?显示时的动画与android native不同。
    • @chitgoks 这可能是因为 Flutter 使用的是它自己的组件,而不是 Android 拥有的原生 View 元素。
    【解决方案3】:

    main.dart

    import 'package:flutter/material.dart';
    import 'package:settings_button/Constants.dart';
    void main() => runApp(new MyApp());
    class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
            return new MaterialApp(
                title: 'Flutter Demo',
                theme: new ThemeData(
                    primarySwatch: Colors.blue,)
                ,
                home: new MyHomePage(title: 'Flutter Demo Home Page'),);
        }
    
    }
    class MyHomePage extends StatefulWidget {
        MyHomePage({
            Key key, this.title
        })
    
            : super(key: key);
        final String title;
        @override
        _MyHomePageState createState() => new _MyHomePageState();
    }
    class _MyHomePageState extends State<MyHomePage> {
        @override
        Widget build(BuildContext context) {
            return new Scaffold(
                appBar: new AppBar(
                    title: new Text(widget.title),
                    actions: <Widget>[
                        PopupMenuButton<String>(
                            onSelected: choiceAction,
                            itemBuilder: (BuildContext context){
                                return Constants.choices.map((String choice){
                                    return PopupMenuItem<String>(
                                        value: choice,
                                        child: Text(choice),);
                                })
                                    .toList();
                            }
                            ,)]
                    ,)
                ,
                body: new Center(
                    child: new Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                            new Text(
                                'Body',)
                            ,]
                        ,)
                    ,)
                ,);
        }
    
        void choiceAction(String choice){
            if(choice == Constants.Settings){
                print('Settings');
            }
            else if(choice == Constants.Subscribe){
                print('Subscribe');
            }
            else if(choice == Constants.SignOut){
                print('SignOut');
            }
        }
    
    }
    

    常量.dart

    class Constants{
      static const String fund = 'Fund';
    //  static const String Settings = 'Settings';
      static const String SignOut = 'Sign out';
    
      static const List<String> choices = <String>[
        fund,`enter code here`
        SignOut
      ];
    }
    

    【讨论】:

      【解决方案4】:

      同样没有警告信息和本地化:

        appBar: AppBar(
          title: Text('Homepage'),
          actions: <Widget>[
            PopupMenuButton<int>(
                onSelected: (item) => handleClick(item),
                itemBuilder: (context) => [
                  PopupMenuItem<int>(value: 0, child: Text('Logout')),
                  PopupMenuItem<int>(value: 1, child: Text('Settings')),
                ],
              ),
          ],
        ),
      
      
      void handleClick(int item) {
        switch (item) {
          case 0:
            break;
          case 1:
            break;
        }
      }
      

      【讨论】:

        【解决方案5】:
        PopupMenuButton<int>(
                itemBuilder: (BuildContext context) => <PopupMenuItem<int>>[
                  new PopupMenuItem<int>(
                      value: 1, child: new Text('Item One')),
                  new PopupMenuItem<int>(
                      value: 2, child: new Text('Item Two')),
                  new PopupMenuItem<int>(
                      value: 3, child: new Text('Item Three')),
                  new PopupMenuItem<int>(
                      value: 4, child: new Text('I am Item Four'))
                ],
                onSelected: (int value) {
                  setState(() { _value = value; });
                })
        

        【讨论】:

          【解决方案6】:

          内部行动列表

                PopupMenuButton(onSelected: menuAction, itemBuilder: (BuildContext itemBuilder) => {'Opt 1', 'Opt 2'}.map((value) => PopupMenuItem(child: Text(value), value: value,)).toList())
          

          物品点击处理方法

            void menuAction(String value) {
             switch (value) {  
              case 'Opt 1':
               print('Hello');
               break;
            }
          }
          

          【讨论】:

            猜你喜欢
            • 2021-08-12
            • 2019-06-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-23
            • 1970-01-01
            相关资源
            最近更新 更多