1

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

 2 years ago
source link: https://www.cnblogs.com/xdd666/p/16222866.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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

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

  • 因为重构涉及到对外暴露的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
  • Config:SmartDialog.config ---> SmartDialog.compatible.config
    • Mac:command + shift + r
    • Windows:ctrl + shift + r

参数移除(必须)⭐️

  • 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等功能
    • 大家按需使用

关闭弹窗时携带数据

该功能和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");
}

永久化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

最小加载时间

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();
}

连续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告别了羞涩,走向了成熟

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK