一、基础概念
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 Statewith 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 Statewith 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弹框的实现方案。除了这两种类型外,还有很多其他类型的弹框类型,每种类型都有自己的实现方式。我们需要具体问题具体分析,灵活运用。在实践中不断探索,准确地找到需要用到的弹框类型,并实现对应的构造器。