Flutter 让你的 Dialog 脱胎换骨吧!(Attach,Dialog,Loading,Toast)
功能更新频繁,请以 github 上都中文介绍为准:https://github.com/fluttercandies/flutter_smart_dialog
前言
Q:你一生中闻过最臭的东西,是什么?
A:我那早已腐烂的梦。
兄弟萌!!!我又来了!
这次,我能自信的对大家说:我终于给大家带了一个,能真正帮助大家解决诸多坑比场景的 pub 包!
将之前的 flutter_smart_dialog,在保持 api 稳定的基础上,进行了各种抓头重构,解决了一系列问题
现在,我终于可以说:它现在是一个简洁,强大,侵入性极低的 pub 包!
关于侵入性问题
之前为了解决返回关闭弹窗,使用了一个很不优雅的解决方法,导致侵入性有点高
这真是让我如坐针毡,如芒刺背,如鲠在喉,这个问题终于搞定了!
同时,我在 pub 包内部设计了一个弹窗栈,能自动移除栈顶弹窗,也可以定点移除栈内标记的弹窗。
存在的问题
使用系统弹窗存在一系列坑,来和各位探讨探讨
必须传 BuildContext
在一些场景必须多做一些传参工作,蛋痛但不难的问题
loading 弹窗
使用系统弹窗做 loading 弹窗,肯定遇到过这个坑比问题
loading 封装在网络库里面:请求网络时加载 loading,手贱按了返回按钮,关闭了 loading
然后请求结束后发现:特么我的页面怎么被关了!!!
系统弹窗就是一个路由页面,关闭系统就是用 pop 方法,这很容易误关正常页面
当然肯定有解决办法,路由监听的地方处理,此处就不细表了
某页面弹出了多个系统 Dialog,很难定点关闭某个非栈顶弹窗
蛋蛋,这是路由入栈出栈机制导致的,理解的同时也一样要吐槽
系统 Dialog,点击事件无法穿透暗色背景
这个坑比问题,我是真没辙
相关思考
上面列举了一些比较常见的问题,最严重的问题,应该就是 loading 的问题
loading 是个超高频使用的弹窗,关闭 loading 弹窗的方法,同时也能关闭正常使用的页面,本身就是一个隐患
穿透 dialog 遮罩是个非常重要的功能,基于该功能,能够在实际业务中,实现很多骚操作
既然在系统 dialog 难以解决各种痛点,加上系统 dialog 也是基于 overlay 去实现的,这样的话,我们也可以去高度定制 overlay!
这次,我要一次性帮各位解决:toast 消息,loading 弹窗,以及更强大的自定义 dialog!
快速上手
初始化
引入(最新版本请点击 pub 查看):pub,github,web effect
接入方式更加简洁😊
极简使用
toast 使用💬
loading 使用⏳
dialog 使用🎨
OK,上面展示了,只需要极少的代码,就可以调用相应的功能
当然,内部还有不少地方做了特殊优化,接下来,我会详细的向大家描述下
你可能会有的疑问
初始化框架的时候,相比以前,居然让大家多写了一个参数,内心十分愧疚😩
关闭页面本质上是一个比较复杂的情况,涉及到
物理返回按键
AppBar 的 back 按钮
手动 pop
为了监控这些情况,不得已增加了一个路由监控参数
实体返回键
对返回按钮的监控,是非常重要的,基本能覆盖大多数情况
pop 路由
虽然对返回按钮的监控能覆盖大多数场景,但是一些手动 pop 的场景就需要新增参数监控
不加
FlutterSmartDialog.observer
如果打开了穿透参数(就可以和弹窗后的页面交互),然后手动关闭页面
就会出现这种很尴尬的情况
加了
FlutterSmartDialog.observer
,就能比较合理的处理了当然,这里的过渡动画,也提供了参数控制是否开启 😉
关于 FlutterSmartDialog.init()
本方法不会占用你的 builder 参数,init 内部回调出来了 builder,你可以大胆放心的继续套
例如:继续套 Bloc 全局实例😄
超实用的参数:backDismiss
这个参数是默认设置为 true,返回的时候会默认关闭弹窗;如果设置为 false,将不会关闭页面
这样就可以十分轻松的做一个紧急弹窗,禁止用户的下一步操作
我们来看一个场景:假定某开源作者决定弃坑软件,不允许用户再使用该软件的弹窗
从上面的效果图可以看出来
点击遮罩,无法关闭弹窗
点击返回按钮无法关闭弹窗
只能点我们自己的按钮,才能关闭弹窗,点击按钮的逻辑可以直接写成关闭 app 之类
只需要俩个简单的参数设置,就能实现这样一个很棒的应急弹窗
设置全局参数
SmartDialog 的全局参数都有着一个比较合理的默认值
为了应付多变的场景,你可以修改符合你自己要求的全局参数
设置符合你的要求的数据,放在 app 入口就行初始化就行
注:如果没有特殊要求,可以不用初始化全局参数(内部皆有默认值)
代码的注释写的很完善,某个参数不明白的,点进去看看就行了
Attach 篇
这是一个很重要的功能,本来早就想加进去了,但是比较忙,一直搁置了;元旦(2022.1.1)开了头,就花了一些时间,完成了这个功能和相关 demo
定位
定位目标 widget 的坐标,这个做起来并不难;但是必须要拿到我们传入的自定义 widget 大小,这样才能将自定义 widget 叠放到一个比较合适的位置(通过一些计算,获取中心点)
实际上 Flutter 提供一个非常合适的组件
CustomSingleChildLayout
,这个组件还提供偏移坐标功能,按理来说非常合适但是,
CustomSingleChildLayout
和SizeTransition
动画控件,存在占位面积冲突,只能使用AnimatedOpacity
渐隐动画位移动画不能用,这我没法忍,抛弃
CustomSingleChildLayout
;使用了各种骚操作,终于拿到自定义 widget 的大小,比较完美实现了效果
定位 dialog,使用 showAttach 方法,参数注释写的相当详细,不明白用法的看看注释就行了
强大的定位功能
必须传目标 widget 的 BuildContext,需要通过它计算出目标 widget 的坐标和大小
动画效果和 show 方法几乎是一致的,为了这个一致的体验,内部做了相当多的针对性优化
自定义坐标点
大多数情况基本都是使用 targetContext
当然还有少数情况,需要使用自定义坐标,此处也提供 target 参数:设置了 target 参数,targetContext 将自动失效
targetContext 是十分常见的场景,所以,这边设置为必传参数,但是你可以给它设置为 null
看来下自定义坐标点效果
模仿 DropdownButton
实际上模仿 DropdownButton 挺不容易的
首先要计算 DropdownButton 控件的位置,在其位置上显示点击后的折叠控件
需要处理 DropdownButton 之外区域的点击事件(点击区域外关闭 DropdownButton)
还需要监听返回事件,手动 pop 路由事件;是这类事件的,需要关闭 DropdownButton
这玩意要自定义,挺让人头大的;但是,现在你可以使用
SmartDialog.showAttach
轻松模仿一个,上述需要注意的事项都帮你处理好了
高亮
这次把遮罩特定区域高亮的功能加上了,这是一个非常实用的功能!
你只需要设置
highlight
参数即可定义高亮的区域,他必须是个不通透的 Widget,例如是 Contaienr,必须设置一个颜色(色值无要求)
使用各种奇形怪状的图片也行,这样就能显示各种复杂图形的高亮区域
highlight 类型是 Positioned,你可以在屏幕上定位任何需要高亮的区域
实际的业务场景
这边举俩个常见的例子,代码有一点点多,就不贴了,感兴趣的请查看:flutter_use
上面俩个业务场景非常常见,有时候,我们需要目标 widget 上面或下面或特定的区域,不被遮罩覆盖
自己去做的话,可以做出来,但是会很麻烦;现在你可以使用showAttach
中的highlight
参数轻松实现这个需求
引导操作
引导操作在 app 上还是非常常见的,需要指定区域高亮,然后介绍其功能
使用
showAttach
中的highlight
参数,也可以轻松实现这个需求,来看下效果代码同样有一点点多,感兴趣的请查看:flutter_use
Dialog 篇
花里胡哨
弹窗从不同位置弹出,动画是有区别的
alignmentTemp:该参数设置不同,动画效果会有所区别
isPenetrateTemp:交互事件穿透遮罩
dialog 栈
这是一个强大且实用的功能!
可以很轻松的定点关闭某个弹窗
Loading 篇
避坑指南
开启 loading 后,可以使用以下方式关闭
SmartDialog.dismiss():可以关闭 loading 和 dialog
status 设置为 SmartStatus.loading:仅仅关闭 loading
一般来说,loading 弹窗是封装在网络库里面的,随着请求状态的自动开启和关闭
基于这种场景,我建议:使用 dismiss 时,加上 status 参数,将其设置为:SmartStatus.loading
坑比场景
网络请求加载的时候,loading 也随之打开,这时很容易误触返回按钮,关闭 loading
当网络请求结束时,会自动调用 dismiss 方法
因为 loading 已被关闭,假设此时页面又有 SmartDialog 的弹窗,未设置 status 的 dismiss 就会关闭 SmartDialog 的弹窗
当然,这种情况很容易解决,封装进网络库的 loading,使用:
SmartDialog.dismiss(status: SmartStatus.loading);
关闭就行了status
参数,是为了精确关闭对应类型弹窗而设计的参数,在一些特殊场景能起到巨大的作用如果大家理解这个参数的含义,那对于何时添加
status
参数,必能胸有成竹
参数说明
参数在注释里面写的十分详细,就不赘述了,来看看效果
maskWidgetTemp:强大的遮罩自定义功能😆,发挥你的脑洞吧。。。
maskColorTemp:支持快捷自定义遮罩颜色
background:支持加载背景自定义
isLoadingTemp:动画效果切换
isPenetrateTemp:交互事件可以穿透遮罩,这是个十分有用的功能,对于一些特殊的需求场景十分关键
自定义 Loading
使用showLoading
可以轻松的自定义出强大的 loading 弹窗;鄙人脑洞有限,就简单演示下
自定义一个 loading 布局
来看看效果
效果一
效果二
效果三
Toast 篇
toast 的特殊性
严格来说,toast 是一个非常特殊的弹窗,我觉得理应具备下述的特征
toast 消息理应一个个展示,后续消息不应该顶掉前面的 toast
这是一个坑点,如果框架内部不做处理,很容易出现后面 toast 会直接顶掉前面 toast 的情况
当然,内部提供了 type 参数,你可以选择你想要的显示逻辑
展示在页面最上层,不应该被一些弹窗之类遮挡
可以发现 loading 和 dialog 的遮罩等布局,均未遮挡 toast 信息
对键盘遮挡情况做处理
键盘这玩意有点坑,会直接遮挡所有布局,只能曲线救国
在这里做了一个特殊处理,当唤起键盘的时候,toast 自己会动态的调整自己和屏幕底部的距离
这样就能起到一个,键盘不会遮挡 toast 的效果
自定义 Toast
参数说明
toast 的一些参数并未向外暴露,仅仅暴露了 msg 和 alignment
例如:toast 字体大小,字体颜色,toast 的背景色等等之类,都没提供参数
一是觉得提供了这些参数,会让整体参数输入变的非常多,乱花渐入迷人眼
二是觉得就算我提供了很多参数,也不一定会满足那些奇奇怪怪的审美和需求
基于上述的考虑,我直接提供了大量的底层参数
你可以随心所欲的定制 toast
注意喔,不仅仅可以定制 toast,例如:成功提示,失败提示,警告提示等等
Toast 做了很多的优化,type 参数,让你能拥有多种显示逻辑,发挥你的想象力吧
注意:使用了
widget
参数,msg
和alignment
参数会失效
调整 toast 显示的位置
更强大的自定义 toast
首先,整一个自定义 toast
使用
效果
骚气的小技巧
有一种场景比较蛋筒
我们使用 StatefulWidget 封装了一个小组件
在某个特殊的情况,我们需要在这个组件外部,去触发这个组件内部的一个方法
对于这种场景,有不少实现方法,但是弄起来可能有点麻烦
这里提供一个简单的小思路,可以非常轻松的触发,组件内部的某个方法
建立一个小组件
展示这个组件,然后外部触发它
来看下效果
最后
相关地址
github:flutter_smart_dialog
文中 demo 地址:flutter_use
demo 演示效果:在线体验
哎,人总是在不断的迷茫中前行。。。
版权声明: 本文为 InfoQ 作者【小呆呆666】的原创文章。
原文链接:【http://xie.infoq.cn/article/9bfad1aa9ce793ffe032ebbac】。文章转载请联系作者。
评论