SmartDialog迁移至4.0:一份真诚的迁移说明


前言

一个开源库,随着不断的迭代优化,难免会遇到一个很痛苦的问题

  • 最初的设计并不是很合理:想添加的很多新功能都受此掣肘

想使得该库更加的强大和健壮,必须要做一个重构

  • 因为重构涉及到对外暴露的api,所以大家会遇到一个比较烦躁的问题:更新版本后,会大面积报错
  • 我考虑了很久,到底怎么帮大家快速迁移呢?最终想到了一个还算合理的方案

对于flutter_smart_dialog 4.0版本的改动,很多是为了解决自己以前考虑不周的历史遗留,以前这个库的初心,主要是为了解决loading和dialog穿透问题;现在扩展到:custom dialog,attach dialog,loading,toast,最初的设计真的力不从心了,config中的api难以去细分的控制这四个模块功能,一些参数的设计基于现在的功能和场景也不太合理等等

希望大家能够理解我为什么要重构🥺,我绝对不是在搞事情🥺

快速迁移指南

兼容API(必须)⭐️

说明

  • show方法快速兼容
SmartDialog.compatible.show(); SmartDialog.compatible.showAttach(); SmartDialog.compatible.showLoading(); SmartDialog.compatible.showToast(); 
  • config快速兼容
SmartDialog.compatible.config; 

增加compatible中间变量,可快速兼容改动的各种参数

快速操作

  • 使用全局替换功能快速迁移:SmartDialog.show ---> SmartDialog.compatible.show
    • Mac:command + shift + r
    • Windows:ctrl + shift + r

SmartDialog迁移至4.0:一份真诚的迁移说明

  • Config:SmartDialog.config ---> SmartDialog.compatible.config
    • Mac:command + shift + r
    • Windows:ctrl + shift + r

SmartDialog迁移至4.0:一份真诚的迁移说明

参数移除(必须)⭐️

  • 4.0版本删除了少量参数
方法 说明
showLoading(...) 删除background参数(compatible不兼容该参数)
showToast(...) 删除alignment参数(compatible不兼容该参数)
showAttach(...) 删除highlight参数(compatible兼容该参数)
  • 删除了这些参数,初始化自定义loading和toast的时候,需要做一点点调整
void main() => runApp(MyApp());  class MyApp extends StatelessWidget {   @override   Widget build(BuildContext context) {     return MaterialApp(       home: HomePage,       // here       navigatorObservers: [FlutterSmartDialog.observer],       // here       builder: FlutterSmartDialog.init(         //default toast widget         toastBuilder: (String msg) => CustomToastWidget(msg: msg),         //default loading widget         loadingBuilder: (String msg) => CustomLoadingWidget(msg: msg),       ),     );   } } 

说明

backgroundalignment这俩个参数实在没什么用,用到的频率实在太低了

一般都是自定义toast和loading样式,想怎么画就怎么画;如果只是简单用下toast和loading,这俩个参数做不到很强的自定义效果,实在过于累赘,索性删除了

参数名变动(可选)

通过上面兼容API参数移除就可以完整迁移了

这里我将变动的参数名完整的写下,大家可以对照下

原参数名 变动参数名
widget builder:和路由dialog参数对齐(具体见下面builder参数说明)
isLoading / isLoadingTemp animationType:方便后期扩展多种动画类型
isPenetrate / isPenetrateTemp usePenetrate:true(点击事件将穿透背景),false(不穿透)
isUseAnimation / isUseAnimationTemp useAnimation:true(使用动画),false(不使用)
clickBgDismiss / clickBgDismissTemp clickMaskDismiss:true(点击遮罩后,关闭dialog),false(不关闭)
animationDuration / animationDurationTemp animationTime:动画持续时间
alignmentTemp alignment:控制弹窗的位置
maskColorTemp maskColor:遮罩颜色
maskWidgetTemp maskWidget:可高度定制遮罩
debounceTemp debounce:防抖功能
time(showToast) displayTime:toast显示的时间
type(showToast) displayType:toast显示逻辑的多种类型

builder参数说明(重要)

4.0版本对自定义控件参数做了很大改变

  • 老版本
SmartDialog.show(   widget: Container(     height: 80,     width: 180,     decoration: BoxDecoration(       color: Colors.black,       borderRadius: BorderRadius.circular(10),     ),     alignment: Alignment.center,     child: Text(       'easy custom dialog',       style: TextStyle(color: Colors.white),     ),   ), ); 
  • 4.0版本
SmartDialog.show(builder: (context) {   return Container(     height: 80,     width: 180,     decoration: BoxDecoration(       color: Colors.black,       borderRadius: BorderRadius.circular(10),     ),     alignment: Alignment.center,     child: Text(       'easy custom dialog',       style: TextStyle(color: Colors.white),     ),   ); }); 

这个改动虽然会让使用麻烦了一点,但是有很重要的意义

  • 首先是为了和路由dialog的api对齐,路由dialog自定义控件参数也是builder
  • 然后解决自定义dialog自身动态刷新问题:自定义布局有TextField,键盘弹起的时候,自定义dialog布局可以动态调整距离(需要使用相应widget)

4.0版本新增功能

强大的Config

  • 可以使用config获取dialog是否存在情况
// 自定义dialog,attach或loading,是否存在在界面上 SmartDialog.config.isExist; // 自定义dialog或attach是否存在在界面上 SmartDialog.config.isExistDialog; // loading是否存在界面上 SmartDialog.config.isExistLoading; // toast是否存在在界面上 SmartDialog.config.isExistToast; 
  • config可以更细致的控制show,showAttach,showLoading,showToast等弹窗
    • SmartConfigXxx()默认参数都是我经过深思后设置的,无特殊要求可以不用额外设置
    • 如果不需要自定义config数值,下方初始化代码无需写
SmartDialog.config   ..custom = SmartConfigCustom()   ..attach = SmartConfigAttach()   ..loading = SmartConfigLoading()   ..toast = SmartConfigToast(); 
  • 可以自定任意config中的数值,以满足相应的需求
    • 下方代码是演示自定义参数
    • 大家可以按需设置
SmartDialog.config   ..custom = SmartConfigCustom(     maskColor: Colors.black.withOpacity(0.35),     useAnimation: true,   )   ..attach = SmartConfigAttach(     animationType: SmartAnimationType.scale,     usePenetrate: false,   )   ..loading = SmartConfigLoading(     clickMaskDismiss: false,     leastLoadingTime: const Duration(milliseconds: 0),   )   ..toast = SmartConfigToast(     intervalTime: const Duration(milliseconds: 100),     displayTime: const Duration(milliseconds: 2000),   ); 

bindPage

说明

这个参数的含义是将SmartDialog将page绑定:如果在SmartDialog上跳转页面

  • 和当前页面绑定SmartDialog会自动隐藏
  • 回到绑定页面的时候,SmartDialog将会显示

关于在Dialog上面跳转页面的问题,4.0之前的版本,可以使用useSystem参数解决

  • 使用useSystem参数时,本质是使用自带dialog作为载体,这样就可以合理的和page交互
  • 但是因为自带dialog的各种局限,使用useSystem时:usePenetratetagKeepSinglepermanent都被禁止使用了

4.0版本引入的bindPage的逻辑,可以避免使用useSystem时的各种限制

bindPage是默认开启的(可在config中配置),也可以在使用show和showAttach时手动关闭或开启;在特殊的业务场景,按需使用bindPageuseSystem即可

使用效果

  • 写个演示demo,这个就是正常在弹窗上跳转页面操作
void _dialogBindPage() async {   var index = 0;   Function()? showDialog;    toNewPage(bool useSystem) async {     Get.to(       () {         return Scaffold(           appBar: AppBar(title: Text('New Page ${++index}')),           body: Container(             color: randomColor(),             alignment: Alignment.center,             child: ElevatedButton(               onPressed: () => showDialog?.call(),               child: Text('test bindPage $index'),             ),           ),         );       },       preventDuplicates: false,     );   }    showDialog = () {     SmartDialog.show(builder: (_) {       return Container(         width: 300,         height: 170,         alignment: Alignment.center,         decoration: BoxDecoration(           color: Colors.white,           borderRadius: BorderRadius.circular(20),         ),         child: ElevatedButton(           onPressed: () => toNewPage(false),           child: Text('test bindPage $index'),         ),       );     });   };    showDialog(); } 
  • 来看看效果
    • 老实说,没有使用useSystem功能时的效果丝滑
    • 但是bindPage也解决了弹窗上跳转页面的问题,同时又保留了usePenetrate,tag,KeepSingle,permanent等功能
    • 大家按需使用

SmartDialog迁移至4.0:一份真诚的迁移说明

关闭弹窗时携带数据

该功能和flutter路由关闭,携带返回数据功能对齐

  • 看下demo:点击show result按钮,关闭弹窗,并将输入框中的数据返回
void _dialogCarryResult() async {   var result = await SmartDialog.show(     builder: (_) {       var message = '';       return Container(         width: 300,         height: 170,         alignment: Alignment.center,         decoration: BoxDecoration(           color: Colors.white,           borderRadius: BorderRadius.circular(20),         ),         child: Column(mainAxisSize: MainAxisSize.min, children: [           Container(             width: 100,             margin: EdgeInsets.only(bottom: 30),             child: TextField(onChanged: (msg) => message = msg),           ),           ElevatedButton(             onPressed: () => SmartDialog.dismiss(result: message),             child: Text('show result'),           )         ]),       );     },   );    SmartDialog.showToast("$result"); } 
  • 效果

SmartDialog迁移至4.0:一份真诚的迁移说明

永久化Dialog

permanent参数设置成true,打开的dialog将变成永久化dialog,框架内部所做的所有兜底关闭操作(返回事件,路由pop,点击遮罩等)将失效,只能手动关闭

该功能请结合实际业务场景使用,请勿滥用

  • 打开一个永久化dialog
SmartDialog.show(   permanent: true,   usePenetrate: true,   builder: (_) => Container(width: 150, height: 150, color: Colors.black), ); 
  • 关闭永久化dialog
SmartDialog.dismiss(force: true); 
  • 来看下demo
void _dialogPermanent() async {   openPermanentDialog() {     SmartDialog.show(       permanent: true,       alignment: Alignment.centerRight,       usePenetrate: true,       clickMaskDismiss: false,       builder: (_) {         return Container(           width: 150,           height: double.infinity,           alignment: Alignment.center,           decoration: BoxDecoration(             color: Colors.white,             borderRadius: BorderRadius.only(               topLeft: Radius.circular(20),               bottomLeft: Radius.circular(20),             ),             boxShadow: [               BoxShadow(color: Colors.grey, blurRadius: 8, spreadRadius: 0.2)             ],           ),           child: Text('permanent dialog'),         );       },     );   }    SmartDialog.show(builder: (_) {     return Container(       width: 300,       height: 170,       alignment: Alignment.center,       decoration: BoxDecoration(         color: Colors.white,         borderRadius: BorderRadius.circular(20),       ),       child: Wrap(spacing: 20, children: [         ElevatedButton(           onPressed: () => openPermanentDialog(),           child: Text('open'),         ),         ElevatedButton(           onPressed: () => SmartDialog.dismiss(force: true),           child: Text('close'),         )       ]),     );   }); } 
  • 效果:可以看见pop路由,点击遮罩和返回事件,都不能关闭permanent dialog

SmartDialog迁移至4.0:一份真诚的迁移说明

最小加载时间

config中loading中有个leastLoadingTime参数,可以控制最小的加载时间

这个功能是为了解决接口请求太快,导致loading弹窗一闪而过的问题

  • 使用:该参数请结合实际业务场景设置合适的数据,leastLoadingTime默认数值为0秒
    • 此处仅做演示,才在此处给config.loading重新赋值,一般建议在app初始化位置就定好参数
    • showLoading()之后立马调用dismiss,loading会一闪而过
    • 设置了leastLoadingTime为2秒,loading会强制等待俩秒之后,dismiss才会生效
void _loadingLeastTime() async {   SmartDialog.config.loading = SmartConfigLoading(     leastLoadingTime: const Duration(seconds: 2),   );   SmartDialog.showLoading();   SmartDialog.dismiss();   SmartDialog.config.loading = SmartConfigLoading(); } 
  • 效果

SmartDialog迁移至4.0:一份真诚的迁移说明

连续toast显示间隔时间

当多个toast连续显示的时候,前一个toast和后一个toast显示无间隔时间,看起来有点突兀

此处在SmartConfigToast中增加了一个intervalTime参数,用以控制间隔时间

默认的intervalTime已经是个合理参数,如无必要,最好不要更改

  • 来看下效果,仅做演示,intervalTime数值就设置稍微大一些
void _toastIntervalTime() async {   SmartDialog.config.toast = SmartConfigToast(     intervalTime: const Duration(milliseconds: 800),   );   for (var i = 0; i < 3; i++) {     SmartDialog.showToast("toast $i").then((value) {       if (!SmartDialog.config.isExistToast) {         SmartDialog.config.toast = SmartConfigToast();       }     });   } } 
  • 效果图

SmartDialog迁移至4.0:一份真诚的迁移说明

总结

SmartDialog 4.0版本是个非常重要的版本,标志着SmartDialog告别了羞涩,走向了成熟

经过这次重构,我也有了信心,去面对更加复杂的业务场景,进行各种拓展

这次重构我做了很多思考,也非常感谢大家给我提个各种issues,是你们启发了我!

SmartDialog迁移至4.0:一份真诚的迁移说明

发表评论

相关文章