乐趣区

关于android:SmartDialog迁移至40一份真诚的迁移说明

前言

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

  • 最后的设计并不是很正当:想增加的很多新性能都受此掣肘

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

  • 因为重构波及到对外裸露的 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:防抖性能

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,是你们启发了我!

退出移动版