如何在 Flutter 中创建自定义下拉列表?

Posted

技术标签:

【中文标题】如何在 Flutter 中创建自定义下拉列表?【英文标题】:How to create custom dropdownlist in Flutter? 【发布时间】:2018-10-05 05:21:47 【问题描述】:

我仍在学习 Flutter,并且正在尝试创建自定义下拉列表。下面是我的自定义下拉列表,它似乎可以工作并返回选定的值,但我仍然需要有关如何在按下墨水池时显示弹出列表的帮助。另外,我如何传入一个字符串数组来构建/填充弹出列表项。感谢您在这方面的帮助。

return new Expanded(
    flex: 4,
    child: new InputDropdownList(
      labelText: "Select a value",
      valueText: viewModel.selectedValue,
      valueStyle: Theme.of(context).inputDecorationTheme.labelStyle,
      items: <String>["ValueA", "ValueB", "ValueC", "ValueD"],
      onPressed: ()  
      ,
      selectedValue: (String value)  
        setState(()  viewModel.selectedValue= value; );
      ,
    ),
),


class InputDropdownList extends StatelessWidget 
  const _InputDropdownList(
    Key key,
    this.labelText,
    this.valueText,
    this.valueStyle,
    this.items,
    this.onPressed,
    this.selectedValue ) : super(key: key);

  final String labelText;
  final String valueText;
  final TextStyle valueStyle;
  final List<String> items;
  final Function() onPressed;
  final ValueChanged<String> selectedValue;

  @override
  Widget build(BuildContext context) 
    return new InkWell(
      onTap: () ,
      child: new InputDecorator(
        decoration: new InputDecoration(
          labelText: labelText,
        ),
        baseStyle: valueStyle,
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            new Text(valueText, style: valueStyle),
            new PopupMenuButton<String>(
              icon: new Icon(Icons.arrow_drop_down, color: Theme.of(context).brightness == Brightness.light ? Colors.grey.shade700 : Colors.white70),
              padding: EdgeInsets.zero,
              onSelected: (value) 
                selectedValue(value);
              ,
              itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
                new PopupMenuItem<String>(
                  value: "ValueA",
                  child: const Text('ValueA')
                ),
                new PopupMenuItem<String>(
                  value: "ValueB",
                  child: const Text('ValueB')
                ),
              ]
            ),
          ],
        ),
      ),
    );
  

【问题讨论】:

您似乎正在尝试在 Flutter 库的菜单页面上重新创建第三个项目(PopupMenuButtonListTile 孩子)。在此处查看源代码github.com/flutter/flutter/blob/master/examples/flutter_gallery/… 如果这接近您想要的,我们可以以此为起点吗? Richard,这正是我想要做的。我尝试使用该示例,但遇到了一个问题,即间距与页面上的其他小部件的高度不一致,我需要为该字段添加标签。我确实设法使用 showMenu 函数让它工作。但是,我仍然有兴趣了解如何从父小部件触发子小部件的 onPress 或 onTap 事件。感谢您对此的帮助。 您现在可能知道影响子小部件的方法是设置您自己的状态,这会导致重新构建子小部件。这允许您在重新构建的子项的构造函数中传递新状态(或其他方式,如 Inherited Widget),并且它们可以适当地显示自己,例如红色而不是蓝色,选中而不是未选中,打开而不是关闭等等。 【参考方案1】:
Here is the dropdown with custom UI,
List<String> slots = [
    '1',
    '2',
    '3',
    '4',
    '5',
];

    List<DropdownMenuItem<String>> mItems = new List();
    
        for (int i = 0; i < slots.length; i++) 
          mItems.add(new DropdownMenuItem(
            child: new Text(slots[i]),
            value: slots[i],
          ));
        
    

    Container(
    height: 50,
    padding: EdgeInsets.only(left: 10, right: 10),
    margin: EdgeInsets.only(
    bottom: 20, left: 15, right: 15),
    alignment: Alignment.center,
        decoration: BoxDecoration(
        color: Colors.grey,
        borderRadius: const BorderRadius.all(
        const Radius.circular(12.0),
        ),
        ),
        child: DropdownButton(
        isExpanded: true,
        underline: Container(),
        icon: Icon(
        Icons.keyboard_arrow_down,
        color: textBlue,
        ),
        hint: Text(
        value,
        style: kTextFieldStyleFill,
        ),
        value: value,
        onChanged: (newValue) 
        setState(() 
        value = newValue;
        );
        ,
        items: mItems,
        ),
    )

【讨论】:

【参考方案2】:

所以这里有两个问题:您想使用List&lt;String&gt; 来填充PopupMenuButton,并且单击InkWell 不会打开弹出菜单。

对于第一个问题,可以创建一个用于生成 PopupMenuItem 列表的函数,以设置在 PopupMenuButton itemBuilder 上。

_popupMenuItems() 
  var popupMenuItemList = <PopupMenuItem<String>>[];
  items.forEach((itemValue) 
    popupMenuItemList.add(
        PopupMenuItem<String>(value: itemValue, child: Text('$itemValue')));
  );
  return popupMenuItemList;

在 PopupMenuButton itemBuilder 中设置_popupMenuItems()

PopupMenuButton<String>(
  ...
  itemBuilder: (BuildContext context) => _popupMenuItems(),
);

至于第二个问题,您提供的示例中的当前设置基础将InkWell 作为父小部件。只有单击PopupMenuButton 时才能显示弹出菜单。使用这种方法,PopupMenuButton 只能在小部件的一小块区域上单击。

InkWell(
  child: InputDecorator(
    child: Row(
      children: <Widget>[
        Text(),
        PopupMenuButton(),
      ],
    ),
  ),
)

作为一种解决方案,PopupMenuButton 可以是 InkWell 的父小部件。这样,单击 PopupMenuButton 中的子项仍应显示弹出菜单。

PopupMenuButton(
  child: InkWell(
    child: InputDecorator(
      child: Row(
        children: <Widget>[
          Text(),
          Icon(),
        ],
      ),
    ),
  ),
)

请注意,您只能在PopupMenuButton 中使用childicon,不能同时使用两者。由于icon不能使用,我们可以在Text旁边设置Icon

这是一个完整的工作示例。

import 'package:flutter/material.dart';

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  var selectedValue = 'Default';
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: InputDropdownList(
          labelText: "Select a value",
          valueText: selectedValue,
          valueStyle: Theme.of(context).inputDecorationTheme.labelStyle,
          items: <String>["ValueA", "ValueB", "ValueC", "ValueD"],
          onPressed: () ,
          selectedValue: (String value) 
            setState(() 
              selectedValue = value;
            );
          ,
        ),
      ), 
    );
  


class InputDropdownList extends StatelessWidget 
  const InputDropdownList(
      Key key,
      this.labelText,
      this.valueText,
      this.valueStyle,
      this.items,
      this.onPressed,
      this.selectedValue)
      : super(key: key);

  final String labelText;
  final String valueText;
  final TextStyle valueStyle;
  final List<String> items;
  final Function() onPressed;
  final ValueChanged<String> selectedValue;

  _popupMenuItems() 
    var popupMenuItemList = <PopupMenuItem<String>>[];
    items.forEach((itemValue) 
      print('$itemValue');
      popupMenuItemList.add(
          PopupMenuItem<String>(value: itemValue, child: Text('$itemValue')));
    );
    return popupMenuItemList;
  

  @override
  Widget build(BuildContext context) 
    return PopupMenuButton<String>(
      child: InkWell(
        // onTap() function overrides the popup displayed from PopupMenuButton
        // onTap: () 
        //   debugPrint('Inkwell tapped');
        // ,
        child: InputDecorator(
          decoration: InputDecoration(
            labelText: labelText,
          ),
          baseStyle: valueStyle,
          child: Row(
            children: [
              Text(valueText, style: valueStyle),
              Icon(Icons.arrow_drop_down,
                  color: Theme.of(context).brightness == Brightness.light
                      ? Colors.grey.shade700
                      : Colors.white70),
            ],
          ),
        ),
      ),
      padding: EdgeInsets.zero,
      onSelected: (value) 
        selectedValue(value);
      ,
      itemBuilder: (BuildContext context) => _popupMenuItems(),
    );
  

【讨论】:

以上是关于如何在 Flutter 中创建自定义下拉列表?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Cards:如何在 Flutter 中创建自定义卡片小部件

在 Flutter 中创建自定义时钟小部件

iOS - 如何在没有第三方框架的情况下在 Swift 中创建自定义动画横幅

编辑表时如何使用数据表在闪亮表中创建下拉列表?

如何在 s-s-rS 中创建下拉过滤器列表?

如何在 GraphQL 中创建自定义对象列表