【问题标题】:How do I use radio buttons inside popup menus?如何在弹出菜单中使用单选按钮?
【发布时间】:2017-10-20 11:57:57
【问题描述】:

我正在尝试创建一个包含可选单选按钮的弹出菜单,以更改视图类型(例如图库、卡片、滑动、网格、列表等)。

我遇到的问题是 PopupMenu 有自己的用于选择值的回调,Radio 和 RadioListTile 也是如此。

忽略 RadioListTile 的 onChanged

这是我的第一次尝试。这实际上有效,只是按钮永远变灰。给 RadioListTiles 一个非空的 noop 函数会导致按钮不再灰显(禁用),但弹出菜单不再起作用。

new PopupMenuButton<String>(
    ...
    itemBuilder: (ctx) => <PopupMenuEntry<String>>[
          new PopupMenuItem(
              child: new RadioListTile(
                  title: new Text("Cards"),
                  value: 'cards',
                  groupValue: _view,
                  onChanged: null),
              value: 'cards'),
          new PopupMenuItem(
              child: new RadioListTile(
                  title: new Text("Swipe"),
                  value: 'swipe',
                  groupValue: _view,
                  onChanged: null),
              value: 'swipe'),
        ],
    onSelected: (String viewType) {
      _view = viewType;
    }));

使用 RadioListTile,忽略 PopupMenu

第二次尝试是完全忽略 PopupMenu,只使用 RadioListTile onChanged。这些按钮不是灰显/禁用的,但也不起作用。

new PopupMenuButton<String>(
  ...
  itemBuilder: (ctx) => <PopupMenuEntry<Null>>[
        new PopupMenuItem(
            child: new RadioListTile(
                title: new Text("Cards"),
                value: 'cards',
                groupValue: _view,
                onChanged: (v) => setState(() => _view = v)),
            value: 'cards'),
        new PopupMenuItem(
            child: new RadioListTile(
                title: new Text("Swipe"),
                value: 'swipe',
                groupValue: _view,
                onChanged: (v) => setState(() => _view = v)),
            value: 'swipe'),
      ],
));

正确的方法是什么? PopupMenu 适用于极其简单的菜单,但元素选择给我带来了冲突。有没有办法获得一个“愚蠢”的弹出菜单,在按钮上显示一列小部件(样式像菜单)?

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    问题在于PopupMenuButton 将弹出对话框保持为私有状态(它甚至将新路由推送到Navigator 堆栈上)。调用 setState 不会重建项目。您可以使用AnimatedBuilderValueNotifier 来解决这个问题。

    这是一个在弹出窗口中工作的单选按钮列表示例:

    import 'package:flutter/foundation.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(new MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          home: new MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      State createState() => new MyHomePageState();
    }
    
    enum Fruit {
      apple,
      banana,
    }
    
    class MyHomePageState extends State<MyHomePage> {
      ValueNotifier<Fruit> _selectedItem = new ValueNotifier<Fruit>(Fruit.apple);
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          body: new Center(
            child: new PopupMenuButton<Fruit>(
              itemBuilder: (BuildContext context) {
                return new List<PopupMenuEntry<Fruit>>.generate(
                  Fruit.values.length,
                  (int index) {
                    return new PopupMenuItem(
                      value: Fruit.values[index],
                      child: new AnimatedBuilder(
                        child: new Text(Fruit.values[index].toString()),
                        animation: _selectedItem,
                        builder: (BuildContext context, Widget child) {
                          return new RadioListTile<Fruit>(
                            value: Fruit.values[index],
                            groupValue: _selectedItem.value,
                            title: child,
                            onChanged: (Fruit value) {
                              _selectedItem.value = value;
                            },
                          );
                        },
                      ),
                    );
                  },
                );
              },
            ),
          ),
        );
      }
    }
    

    【讨论】:

    • 我刚刚查看了 CheckedPopupMenuItem 类。引入选择用作引导小部件的图标的可能性似乎不需要太多工作,不是吗?您认为为此提出拉取请求会浪费精力吗?
    • 除非你有办法让一个项目强制其他项目重建,否则它并不能真正解决你的问题。
    • 弹出菜单宽度可以调整吗?我想把它做得更小,想去掉所有的空白,让它真正适合一个。帮助
    【解决方案2】:

    我认为对您来说最好的解决方案是使用CheckedPopupMenuItems 而不是广播列表。功能应该正是您想要实现的,不是吗?

    这是一个小例子:

    import 'package:flutter/widgets.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(new MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          home: new MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      String _selectedView = 'Card';
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('TestProject'),
            actions: <Widget>[
              new PopupMenuButton(
                onSelected: (value) => setState(() => _selectedView = value),
                itemBuilder: (_) => [
                      new CheckedPopupMenuItem(
                        checked: _selectedView == 'Card',
                        value: 'Card',
                        child: new Text('Card'),
                      ),
                      new CheckedPopupMenuItem(
                        checked: _selectedView == 'Swipe',
                        value: 'Swipe',
                        child: new Text('Swipe'),
                      ),
                      new CheckedPopupMenuItem(
                        checked: _selectedView == 'List',
                        value: 'List',
                        child: new Text('List'),
                      ),
                    ],
              ),
            ],
          ),
          body: new Center(child: new Text(_selectedView)),
        );
      }
    }
    

    【讨论】:

    • 它很接近并且运行良好,但我仍然希望拥有单选按钮,因为它们更熟悉。我可能只是看一下 CheckedPopupMenuItem 的来源,然后从那里开始。
    • 这个答案可能不是@perlatus 想要的。但是它对我来说非常有效,因为我正在寻找一种在弹出菜单中设置和取消设置复选框的方法
    猜你喜欢
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多