如何在 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 库的菜单页面上重新创建第三个项目(PopupMenuButton
和 ListTile
孩子)。在此处查看源代码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<String>
来填充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
中使用child
或icon
,不能同时使用两者。由于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 中创建自定义卡片小部件