一、基础概念
Flutter中的弹框分为两种类型:Dialog和BottomSheet。Dialog一般指具有模态的弹框,使用showDialog函数实现;而BottomSheet一般指非模态的弹框,使用showModalBottomSheet实现。除此之外,还有一些其他类型的弹框,如底部菜单弹框,选择器弹框等,这里就不一一列举了。
Flutter的弹框构造器通常包括以下几个部分:弹框主体Widget、背景遮罩Widget、动画控制器、弹框位置等等。接下来我们会重点讲述这些部分的实现过程。
二、Dialog的实现
Dialog是模态的弹框类型,即弹框出现时,背景被遮挡且无法操作。
1、弹框主体Widget
在Flutter中,Dialog通常由一个AlertDialog Widget或SimpleDialog Widget构成。其中AlertDialog可以自定义其标题、内容和按钮;而SimpleDialog只包含多个选项。
AlertDialog的构建过程类似下面的代码:
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("弹框标题"),
content: Text("弹框内容"),
actions: [
FlatButton(
child: Text("取消"),
onPressed: () {
Navigator.of(context).pop(); // 关闭弹框
},
),
FlatButton(
child: Text("确定"),
onPressed: () {
// 实现确认逻辑
},
),
],
);
},
);
2、背景遮罩Widget
这里我们使用了showDialog函数来构建Dialog,同时此函数还允许我们自定义弹框显示时的遮罩背景。这可以通过指定barrierColor、barrierOpacity和barrierDismissible等属性来实现。其中,barrierColor和barrierOpacity用于设置遮罩的颜色和透明度,而barrierDismissible则用于控制是否允许用户点击遮罩背景来关闭弹框(即点击空白处关闭弹框)。
showDialog(
context: context,
barrierColor: Colors.black12, // 遮罩颜色
barrierOpacity: 0.5, // 遮罩透明度
barrierDismissible: false, // 是否允许点击空白处关闭弹框
builder: (BuildContext context) {
return AlertDialog(
//...
);
},
);
3、动画控制器
想要Dialog具有更好的动画效果,我们可以使用Flutter内置的动画库Animations。通过AnimatedWidget或AnimatedBuilder等顶层Widget,我们可以方便地构建各种动画效果。这里以FadeTransition为例,演示如何实现Dialog的淡入淡出效果。
class MyDialog extends StatefulWidget {
const MyDialog({Key key}) : super(key: key);
@override
_MyDialogState createState() => _MyDialogState();
}
class _MyDialogState extends State with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_animation = CurvedAnimation(parent: _controller, curve: Curves.easeOut);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _animation,
child: Center(
child: AlertDialog(
title: Text("弹框标题"),
content: Text("弹框内容"),
actions: [
FlatButton(
child: Text("取消"),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text("确定"),
onPressed: () {
//...
},
),
],
),
),
);
}
}
void showMyDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return MyDialog();
},
);
}
三、BottomSheet的实现
BottomSheet是非模态的弹框类型,即弹框出现时,背景不被遮挡且可以进行操作。BottomSheet有两种类型:PersistentBottomSheet和ModalBottomSheet。其中,PersistentBottomSheet会一直保持显示直至手动关闭,而ModalBottomSheet会在点击某个按钮后弹出,在外部区域进行操作时自动隐藏。
1、弹框主体Widget
在Flutter中,BottomSheet的构建器是builder属性,它是个函数类型,返回一个Widget。另外我们也可以使用官方提供的BottomSheet Widget。与Dialog不同,BottomSheet不包含标题和按钮等元素,通常只包含一部分滚动内容。
ModalBottomSheet(
builder: (BuildContext context) {
return Container(
height: 200.0,
child: ListView(
children: [
ListTile(title: Text('选项1')),
ListTile(title: Text('选项2')),
ListTile(title: Text('选项3')),
ListTile(title: Text('选项4')),
],
),
);
},
);
2、背景遮罩Widget
与Dialog类似,BottomSheet也有相应的遮罩背景设置属性。但由于其本身不是模态的,所以不需要只读化背景,也就意味着无需设置barrierDismissible属性。
showModalBottomSheet(
context: context,
backgroundColor: Colors.black12, // 设置背景色
builder: (BuildContext context) {
return Container(
height: 200.0,
child: ListView(
children: [
//...
],
),
);
},
);
3、动画控制器
维护动画控制器实现BottomSheet的进入和退出动画。
class MyBottomSheet extends StatefulWidget {
const MyBottomSheet({Key key}) : super(key: key);
@override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_animation = CurvedAnimation(parent: _controller, curve: Curves.easeOut);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: Tween(
begin: Offset(0.0, 1.0),
end: Offset(0.0, 0.0),
).animate(_controller),
child: Container(
height: 200.0,
child: ListView(
children: [
//...
],
),
),
);
}
}
void showMyBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return MyBottomSheet();
},
);
}
四、结语
以上就是Flutter弹框的实现方案。除了这两种类型外,还有很多其他类型的弹框类型,每种类型都有自己的实现方式。我们需要具体问题具体分析,灵活运用。在实践中不断探索,准确地找到需要用到的弹框类型,并实现对应的构造器。