作者 | 前行的乌龟 地址 | juejin.im/post/5dbff51bf265da4d4e3001b2
前言
Flutter 里面的谭庄不管是重量级的还是轻量级的都在这里了:
-
DropdownButton
– 下拉菜单按钮 -
BottomSheet
– 底部弹出弹窗 -
PopupMenuButton
– pop 按钮 -
Dialog
– 对话框 -
Toast
– Flutter 没有内置 Toast,所有的 Toast 方案都是以外置插件的方式导进来使用的,这里多介绍几个 -
OKToast
– 最好的 Toast 插件,功能非常完善,推荐使用 -
SnackBar
– 喜闻乐见了啊,OKToast 其实已经可以取代 SnackBar 了,官方原生的 SnackBar 很死板
详解
DropdownButton
DropdownButton
是一个简单的下拉选择框,构建特点:-
不管是 hint
的样式还是可选择
的样式都是 widget -
每一项都是特定的 widget 类型: DropdownMenuItem
,大家在其内部再写具体的 widget 样式,不过样式是自己写,但是DropdownMenuItem
内部有个value
对应该选项的值,这个必须要写的 -
当前选项的变化需要我们自己维护, DropdownButton
是不会帮我们做的

-
hint
– value == null 时显示的文字 -
disabledHint
– 禁用的提示 -
items
– 选项 item,注意是值是列表类型 -
style
– 字体样式 -
iconSize
– 右侧三角大小 -
isDense
– true: item 高度是下拉框高度的一半,false: 下拉框高度和 item 一样 -
isExpanded
– false:下拉框最小宽度 true: 充满父容器 -
value
– 当前选中的那项 -
onChanged
– 选中事件
String selectValue;
@override
Widget build(BuildContext context) {
return DropdownButton(
hint: Text(“请选择您要的号码:”),
items: getItems(),
value: selectValue,
onChanged: (value) {
print(value);
setState(() {
selectValue = value;
});
},
);
}
getItems() {
var items = List<DropdownMenuItem<String>>();
items.add(DropdownMenuItem(child: Text(“AA”), value: “11”));
items.add(DropdownMenuItem(child: Text(“BB”), value: “22”,));
items.add(DropdownMenuItem(child: Text(“CC”), value: “33”,));
items.add(DropdownMenuItem(child: Text(“DD”), value: “44”,));
items.add(DropdownMenuItem(child: Text(“EE”), value: “55”,));
return items;
}
}
1 |
DropdownMenuItem
选项列表时要指定数值类型 List<DropdownMenuItem<String>>()
,要不 selectValue
那里就不能写具体的数值类型,只能写 var
了BottomSheet
BottomSheet
很像 android 的 BottomSheetBehavior,不过不能向往拖拽成一个页面
child: Text(‘点击’),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min, // 设置最小的弹出
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text(“Camera”),
onTap: () async {
},
),
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text(“Gallery”),
onTap: () async {
},
),
],
);
}
);
},
)
1 |
PopupMenuButton
PopupMenuButton
android 里的 PopupWindow
大家很熟悉吧,这个就是 Flutter 版的
itemBuilder
构建弹出菜单样式,是 list 结构的数据,使用PopupMenuItem
承载每个 item ,但是 list 外层的泛型要用List<PopupMenuEntry<String>>
,非常蛋疼,说实话 itemBuilder这里的 API 我是真不喜欢,太难用了,和
DropdownButton的设计都不统一,对于
itemBuilder内部的实现类谁关心呢,根本就不应该把
PopupMenuEntry` 暴露出来。写法固定的,大家记住吧elevation
阴影高度padding
边距child
按钮样式和icon
互斥,只能用一个icon
按钮样式和child
互斥,只能用一个offset
偏移量,offset 的值>100 比如:offset(100,100)
就是在 actionBar 的正下面onSelected
用户选中的回调onCanceled
用户取消的回调配合 actionBar 的写法:
var items = <String>[“AA”, “BB”, “CC”, “DD”, “FF”];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
PopupMenuButton<String>(
itemBuilder: (BuildContext context) {
return _getItemBuilder2();
},
icon: Icon(Icons.access_alarm),
onSelected: (value) {
print(value);
},
onCanceled: () {},
offset: Offset(200, 100),
)
],
),
body: Center(
child: TestWidget(),
),
);
}
}
1 |
return items
.map((item) => PopupMenuItem<String>(
child: Text(item),
value: item,
))
.toList();
}
1 |
return <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: “1”,
child: ListTile(
leading: Icon(Icons.share),
title: Text(‘分享’),
),
),
PopupMenuDivider(), //分割线
PopupMenuItem<String>(
value: “2”,
child: ListTile(
leading: Icon(Icons.settings),
title: Text(‘设置’),
),
),
];
}
1 |

+-
代表左右方向,在下方按钮显示,Y 坐标写 100 就行AlertDialog
1. 明确 Flutter 中 dialog 的基本特性
Flutter
中dialog
实际上是一个由route
直接切换显示的页面,所以使用Navigator.of(context) 的 push、pop(xx)
方法进行显示、关闭、返回数据Flutter
中有两种风格的dialog
showDialog()
启动的是material
风格的对话框showCupertinoDialog()
启动的是ios
风格的对话框
Flutter
中有两种样式的dialog
SimpleDialog
使用多个SimpleDialogOption
为用户提供了几个选项AlertDialog
一个可选标题 title 和一个可选列表的 actions 选项
2. showDialog
方法讲解
@required BuildContext context,
bool barrierDismissible = true,
@Deprecated(
‘Instead of using the “child” argument, return the child from a closure ‘
‘provided to the “builder” argument. This will ensure that the BuildContext ‘
‘is appropriate for widgets built in the dialog.’
) Widget child,
WidgetBuilder builder,
}) {
…….
}
1 |
context
上下文对象barrierDismissible
点外面是不是可以关闭,默认是 true 可以关闭的builder
是 widget 构造器FlatButton
标准 AlertDialog 中的按钮必须使用这个类型Navigator.of(context).pop();
对话框内关闭对话框
3. 对话框显示层级

4. AlertDialog
AlertDialog
作者非常 Nice,从使用习惯上就考虑照顾从 android 切过来的开发者,比其他一些 widget 的作者要强多了

show(BuildContext context,) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: Text(“这里是测试标题”),
actions: <Widget>[
FlatButton(
child: Text(“删除”),
onPressed: () {
print(“删除”);
Navigator.of(context).pop();
},
),
FlatButton(
child: Text(“取消”),
onPressed: () {
print(“取消”);
Navigator.of(context).pop();
},
),
],
);
},
);
}
// 使用对话框
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.adb),
tooltip: “tips”,
backgroundColor: Colors.blueAccent,
foregroundColor: Colors.amberAccent,
onPressed: () {
show(context);
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.startTop,
body: Center(
child: TestWidget(),
),
);
}
1 |
5. 自定义对话框
showDialog
方法中的 builder
我们传自己的样式就是自定义 dialog 了,很简单不是,Flutter 基本上就是这个套路,大家要熟悉啊
@override
State<StatefulWidget> createState() {
return TestDialogState();
}
}
class TestDialogState extends State<TestDialog> {
var num = 0;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(num.toString(),style: TextStyle(decoration: TextDecoration.none),),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text(“+”),
onPressed: () {
setState(() {
num++;
});
},
),
RaisedButton(
child: Text(“-“),
onPressed: () {
setState(() {
num–;
});
},
),
],
),
],
);
}
}
1 |
showDialog(
context: context,
builder: (context) {
return TestDialog();
});
},
1 |
6. SimpleDialog
SimpleDialog
的样式
context: context,
builder: (context) {
return new SimpleDialog(
title: new Text(“SimpleDialog”),
children: <Widget>[
new SimpleDialogOption(
child: new Text(“SimpleDialogOption One”),
onPressed: () {
Navigator.of(context).pop(“SimpleDialogOption One”);
},
),
new SimpleDialogOption(
child: new Text(“SimpleDialogOption Two”),
onPressed: () {
Navigator.of(context).pop(“SimpleDialogOption Two”);
},
),
new SimpleDialogOption(
child: new Text(“SimpleDialogOption Three”),
onPressed: () {
Navigator.of(context).pop(“SimpleDialogOption Three”);
},
),
],
);
});
1 |
7. iOS 风格的 dialog

var dialog = CupertinoAlertDialog(
content: Text(
“你好,我是你苹果爸爸的界面”,
style: TextStyle(fontSize: 20),
),
actions: <Widget>[
CupertinoButton(
child: Text(“取消”),
onPressed: () {
Navigator.pop(context);
},
),
CupertinoButton(
child: Text(“确定”),
onPressed: () {
Navigator.pop(context);
},
),
],
);
showDialog(context: context, builder: (_) => dialog);
}
1 |
8. 一些坑
自定义的 dialog 要是太长了超过屏幕长度了,请在外面加一个可以滚动的 SingleChildScrollView 自定义的 dialog 要是有 ListView 的话,必须在最外面加上一个确定宽度和高度的 Container,要不会报错,道理和上面的那条一样的

发布者:秦子帅,转转请注明出处:http://qinzishuai.cn/7066/0e2dbdc8d8/