⼀种更优雅的FlutterDialog解决⽅案
为了应对复杂的业务场景,同时降低侵⼊性,在保持api稳定基础上,全⾯重构了SmartDialog底层
我现在可以⾃信的说:它现在是⼀个简洁,强⼤,侵⼊性极低的Pub包
请使⽤Flutter 2.0及其以上的⼩伙伴们移步:
前⾔
系统⾃带的Dialog实际上就是Push了⼀个新页⾯,这样存在很多好处,但是也存在⼀些很难解决的问题
必须传BuildContext
loading弹窗⼀般都封装在⽹络框架中,多传个context参数就很头疼;⽤fish_redux还好,effect层直接能拿到context,要是⽤bloc还得在view层把context传到bloc或者cubit⾥⾯。。。
⽆法穿透暗⾊背景,点击dialog后⾯的页⾯
这个是真头痛,想了很多办法,都没能在⾃带的dialog上⾯解决这个问题
系统⾃带Dialog写成的Loading弹窗,在⽹络请求和跳转页⾯的情况,会存在路由混乱的情况
情景复盘:loading库⼀般封装在⽹络层,某个页⾯提交完表单,要跳转页⾯,提交操作完成,进⾏页⾯跳转,loading关闭是在异步回调中进⾏(onError或者onSuccess),会出现执⾏了跳转操作时,弹窗还未关闭,延时⼀⼩会关闭,因为⽤的都是pop页⾯⽅法,会把跳转的页⾯pop掉
上⾯是⼀种很常见的场景,涉及到复杂场景更加难以预测,解决⽅法也有:定位页⾯栈的栈顶是否是Loading弹窗,选择性Pop,实现⿇烦
上⾯这些痛点,简直个个致命,当然,还存在⼀些其它的解决⽅案,例如:
页⾯顶级使⽤Stack
使⽤Overlay
很明显,使⽤Overlay可移植性最好,⽬前很多toast和dialog三⽅库便是使⽤该⽅案,使⽤了⼀些loading库,看了其中源码,穿透背景解决⽅案,和预期想要的效果⼤相径庭、⼀些dialog库⾃带toast显⽰,但是toast显⽰却⼜不能和dialog共存(toast属于特殊的信息展⽰,理应能独⽴存在),导致我需要多依赖⼀个Toast库
SmartDialog
基于上⾯那些难以解决的问题,只能⾃⼰去实现,花了⼀些时间,实现了⼀个Pub包,基本该解决的痛点都已解决了,⽤于实际业务没什么问题
效果
引⼊
Pub:
⾃2.0版本开始,本库已适配空安全
dependencies:
flutter_smart_dialog: any
注意:该库已迁移空安全,注意版本区分
# ⾮空安全前最后⼀个稳定版本
dependencies:
flutter_smart_dialog: ^1.3.1
使⽤
主⼊⼝配置
在主⼊⼝这地⽅需要配置下,这样就可以不传BuildContext使⽤Dialog了
只需要在MaterialApp的builder参数处配置下即可
void main() {
runApp(MyApp());
}
///flutter 2.0
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Container(),
builder: (BuildContext context, Widget? child) {
return FlutterSmartDialog(child: child);
},
);
}
}
///flutter 1.x
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Container(),
builder: (BuildContext context, Widget child) {
return FlutterSmartDialog(child: child);
},
);
}
}
使⽤FlutterSmartDialog包裹下child即可,下⾯就可以愉快的使⽤SmartDialog了
使⽤Toast:因为toast特殊性,此处单独对toast做了⼀些优化
msg:必传参数
time:可选,Duration类型,默认2000ms
widget:可选,可以⾃定义toast
alignment:可选,控制toast位置
如果想使⽤花⾥胡哨的Toast效果,请使⽤showToast⽅法定制就⾏了,炒鸡简单喔,懒得⾃⼰写的,抄下我的ToastWidget,改下属性就⾏了哈
SmartDialog.showToast('test toast');
使⽤Loading:loading拥有诸多设置属性,参照下⽅的SmartDialog配置参数说明即可
msg:可选,loading动画下⾯的⽂字信息(默认:加载中…)
//open loading
SmartDialog.showLoading();
//delay off
await Future.delayed(Duration(seconds: 2));
flutter pubSmartDialog.dismiss();
⾃定义dialog
使⽤SmartDialog.show()⽅法即可,⾥⾯含有众多Temp为后缀的参数,和下述⽆Temp为后缀的参数功能⼀致
特殊属性isUseExtraWidget:是否使⽤额外覆盖浮层,可与主浮层独⽴开;可与loading,dialog之类独⽴开,⾃带的showToast 便是开启了该配置,可与loading共存
SmartDialog.show(
alignmentTemp: Alignment.bottomCenter,
clickBgDismissTemp: true,
widget: Container(
color: Colors.blue,
height: 300,
),
);
SmartDialog配置参数说明
为了避免instance⾥⾯暴露过多属性,导致使⽤不便,此处诸多参数使⽤instance中的config属性管理
使⽤config设置的属性都是全局的,将这些属性单独使⽤Config管理,是为了⽅便修改和管理这些属性,也是为了使SmartDialog类更易维护
参数功能说明
alignment
控制⾃定义控件位于屏幕的位置
<: ⾃定义控件位于屏幕中间,且是动画默认为:渐隐和缩放,可使⽤isLoading选择动画Alignment.bottomCenter、Alignment.bottomLeft、Alignment.bottomRight:⾃定义控件位于屏幕底部,动画默认为位移动
画,⾃下⽽上,可使⽤animationDuration设置动画时间
下,可使⽤animationDuration设置动画时间
isPenetrate 默认:false;是否穿透遮罩背景,交互遮罩之后控件,true:点击能穿透背景,false:不能穿透;穿透遮罩设置为true,背景遮罩会⾃
动变成透明(必须)
clickBgDismiss默认:true;点击遮罩,是否关闭dialog—true:点击遮罩关闭dialog,false:不关闭maskColor遮罩颜⾊(isPenetrate为true,该参数失效)
maskWidget可⾼度⾃定义遮罩样式,使⽤该参数,maskColor失效(isPenetrate为true,该参数失效)animationDuration动画时间
isUseAnimation默认:true;是否使⽤动画
isLoading默认:true;是否使⽤Loading动画;true:内容体使⽤渐隐动画 false:内容体使⽤缩放动画,仅仅针对中间位置的dialog isExist状态标定:loading和⾃定义dialog 是否存在在界⾯上
isExistMain状态标定:⾃定义dialog 是否存在在界⾯上(show)
isExistLoading状态标定:loading是否存在界⾯上(showLoading)
isExistToast状态标定:toast是否存在在界⾯上(showToast)
Config属性使⽤,举个栗⼦
内部已初始化相关属性;如果需要定制,可在主⼊⼝处,初始化⾃⼰想要的属性
fig
..clickBgDismiss = true
..isLoading = true
..isUseAnimation = true
..animationDuration = Duration(milliseconds: 270)
..isPenetrate = false
..maskColor = Colors.black.withOpacity(0.1)
..alignment = ;
返回事件,关闭弹窗解决⽅案
使⽤Overlay的依赖库,基本都存在⼀个问题,难以对返回事件的监听,导致触犯返回事件难以关闭弹窗布局之类,想了很多办法,没办法在依赖库中解决该问题,此处提供⼀个BaseScaffold,在每个页⾯使⽤BaseScaffold,便能解决返回事件关闭Dialog问题
Flutter 2.0
typedef ScaffoldParamVoidCallback = void Function();
class BaseScaffold extends StatefulWidget {
const BaseScaffold({
Key? key,
this.appBar,
this.body,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.floatingActionButtonAnimator,
this.persistentFooterButtons,
this.drawer,
this.bottomNavigationBar,
this.bottomSheet,
this.backgroundColor,
this.primary = true,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.drawerScrimColor,
this.drawerEdgeDragWidth,
this.drawerEnableOpenDragGesture = true,
this.isTwiceBack = false,
this.isCanBack = true,
}) : super(key: key);
final bool extendBody;
final bool extendBodyBehindAppBar;
final PreferredSizeWidget? appBar;
final Widget? body;
final Widget? floatingActionButton;
final FloatingActionButtonLocation? floatingActionButtonLocation;
final FloatingActionButtonAnimator? floatingActionButtonAnimator;
final List<Widget>? persistentFooterButtons;
final Widget? drawer;
final Widget? endDrawer;
final Color? drawerScrimColor;
final Color? backgroundColor;
final Widget? bottomNavigationBar;
final Widget? bottomSheet;
final bool? resizeToAvoidBottomInset;
final bool primary;
final DragStartBehavior drawerDragStartBehavior;
final double? drawerEdgeDragWidth;
final bool drawerEnableOpenDragGesture;
final bool endDrawerEnableOpenDragGesture;
/
/custom param
final bool isTwiceBack;
final bool isCanBack;
final ScaffoldParamVoidCallback? onBack;
@override
_BaseScaffoldState createState() => _BaseScaffoldState();
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论