如何在弹出菜单中使用单选按钮?

时间:2017-05-20 11:52:38

标签: dart flutter

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

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

忽略RadioListTile的onChanged

这是我的第一次尝试。这实际上是有效的,除了按钮永远变灰。给RadioListTiles一个非null的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适用于非常简单的菜单,但元素选择给我带来了冲突。有没有办法让一个“哑”的弹出菜单在按钮上显示一小部分小部件(样式菜单)?

2 个答案:

答案 0 :(得分:1)

我认为最好的解决方案是使用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)),
    );
  }
}

答案 1 :(得分:1)

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

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

screenshot

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;
                        },
                      );
                    },
                  ),
                );
              },
            );
          },
        ),
      ),
    );
  }
}