一种更优雅的 Flutter Dialog 解决方案
前言
系统自带的 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 包,基本该解决的痛点都已解决了,用于实际业务没什么问题
效果
引入
自 2.0 版本开始,本库已适配空安全
注意:该库已迁移空安全,注意版本区分
使用
主入口配置
在主入口这地方需要配置下,这样就可以不传 BuildContext 使用 Dialog 了
只需要在 MaterialApp 的 builder 参数处配置下即可
使用FlutterSmartDialog
包裹下 child 即可,下面就可以愉快的使用 SmartDialog 了
使用 Toast:因为 toast 特殊性,此处单独对 toast 做了一些优化
time:可选,Duration 类型,默认 1500ms
isDefaultDismissType:toast 消失的类型,默认 true
true:默认消失类型,类似 android 的 toast,toast 一个一个展示
false:非默认消失类型,多次点击,后面 toast 会顶掉前者的 toast 显示
widget:可以自定义 toast
msg:必传信息
alignment:可选,控制 toast 位置
如果想使用花里胡哨的 Toast 效果,请使用 showToast 方法定制就行了,炒鸡简单喔,懒得自己写的,抄下我的 ToastWidget,改下属性就行了哈
使用 Loading:loading 拥有诸多设置属性,参照下方的
SmartDialog配置参数说明
即可msg:可选,loading 动画下面的文字信息(默认:加载中...)
自定义 dialog
使用 SmartDialog.show()方法即可,里面含有众多
Temp
为后缀的参数,和下述无Temp
为后缀的参数功能一致特殊属性
isUseExtraWidget
:是否使用额外覆盖浮层,可与主浮层独立开;可与 loading,dialog 之类独立开,自带的 showToast 便是开启了该配置,可与 loading 共存
SmartDialog 配置参数说明
为了避免
instance
里面暴露过多属性,导致使用不便,此处诸多参数使用instance
中的config
属性管理使用 config 设置的属性都是全局的,将这些属性单独使用 Config 管理,是为了方便修改和管理这些属性,也是为了使 SmartDialog 类更易维护
Config 属性使用,举个栗子
内部已初始化相关属性;如果需要定制,可在主入口处,初始化自己想要的属性
返回事件,关闭弹窗解决方案
使用 Overlay 的依赖库,基本都存在一个问题,难以对返回事件的监听,导致触犯返回事件难以关闭弹窗布局之类,想了很多办法,没办法在依赖库中解决该问题,此处提供一个BaseScaffold
,在每个页面使用BaseScaffold
,便能解决返回事件关闭 Dialog 问题
Flutter 2.0
Flutter 1.x
几个问题解决方案
穿透背景
穿透背景有俩个解决方案,这里都说明下
AbsorbPointer、IgnorePointer
当时想解决穿透暗色背景,和背景后面的控件互动的时候,我几乎立马想到这俩个控件,先了解下这俩个控件吧
AbsorbPointer
阻止子树接收指针事件,
AbsorbPointer
本身可以响应事件,消耗掉事件absorbing
属性(默认 true)true:拦截向子 Widget 传递的事件 false:不拦截
IgnorePointer
阻止子树接收指针事件,
IgnorePointer
本身无法响应事件,其下的控件可以接收到点击事件(父控件)ignoring
属性(默认 true)true:拦截向子 Widget 传递的事件 false:不拦截
分析
这里来分析下,首先
AbsorbPointer
这个控件是不合适的,因为AbsorbPointer
本身会消费触摸事件,事件被AbsorbPointer
消费掉,会导致背景后的页面无法获取到触摸事件;IgnorePointer
本身无法消费触摸事件,又由于IgnorePointer
和AbsorbPointer
都具有屏蔽子 Widget 获取触摸事件的作用,这个貌似靠谱,这里试了,可以和背景后面的页面互动!但是又存在一个十分坑的问题因为使用
IgnorePointer
屏蔽子控件的触摸事件,而IgnorePointer
本身又不消耗触摸事件,会导致无法获取到背景的点击事件!这样点击背景会无法关闭 dialog 弹窗,只能手动关闭 dialog;各种尝试,实在没办法获取到背景的触摸事件,此种穿透背景的方案只能放弃
Listener、behavior
这种方案,成功实现想要的穿透效果,这里了解下behavior
的几种属性
deferToChild:仅当一个孩子被命中测试击中时,屈服于其孩子的目标才会在其范围内接收事件
opaque:不透明目标可能会受到命中测试的打击,导致它们既在其范围内接收事件,又在视觉上阻止位于其后方的目标也接收事件
translucent:半透明目标既可以接收其范围内的事件,也可以在视觉上允许目标后面的目标也接收事件
有戏了!很明显 translucent 是有希望的,尝试了几次,然后成功实现了想要的效果
注意,这边有几个坑点,提一下
务必使用
Listener
控件来使用 behavior 属性,使用 GestureDetector 中 behavior 属性会存在一个问题,一般来说:都是 Stack 控件里面的 Children,里面有俩个控件,分上下层,在此处,GestureDetector 设置 behavior 属性,俩个 GestureDetector 控件上下叠加,会导致下层 GestureDetector 获取不到触摸事件,很奇怪;使用Listener
不会产生此问题我们的背景使用
Container
控件,我这里设置了Colors.transparent
,直接会导致下层接受不到触摸事件,color 为空才能使下层控件接受到触摸事件,此处不要设置 color 即可
下面是写的一个验证小示例
Toast 和 Loading 冲突
这个问题,从理论上肯定会存在的,因为一般 Overlay 库只会使用一个 OverlayEntry 控件,这会导致,全局只能存在一个浮窗布局,Toast 本质是一个全局弹窗,Loading 也是一个全局弹窗,使用其中一个都会导致另一个消失
Toast 明显是应该独立于其他弹窗的一个消息提示,封装在网络库中的关闭弹窗的 dismiss 方法,也会将 Toast 消息在不适宜的时候关闭,在实际开发中就碰到此问题,只能多引用一个 Toast 三方库来解决,在规划这个 dialog 库的时候,就想到必须解决此问题
此处内部多使用了一个 OverlayEntry 来解决该问题,提供了相关参数来分别控制,完美使 Toast 独立于其它的 dialog 弹窗
多增加一个 OverlayEntry 都会让内部逻辑和方法使用急剧复杂,维护也会变得不可预期,故额外只多提供一个 OverlayEntry;如果需要更多,可 copy 本库,自行定义,实现该库相关源码,都力求能让人看明白,相信大家 copy 使用时不会感到晦涩难懂
FlutterSmartDialog 提供
OverlayEntry
和OverlayEntryExtra
可以高度自定义,相关实现,可查看内部实现FlutterSmartDialog 内部已进行相关实现,使用
show()
方法中的isUseExtraWidget
区分
最后
这个库花了一些时间去构思和实现,算是解决几个很大的痛点
如果大家对
返回事件
有什么好的处理思路,麻烦在评论里告知,谢谢!
项目地址
FlutterSmartDialog 一些信息
Github:flutter_smart_dialog
使用效果体验:点击体验一下
系列文章
状态管理
版权声明: 本文为 InfoQ 作者【小呆呆666】的原创文章。
原文链接:【http://xie.infoq.cn/article/8c7bfb094f4faf297a4c7892c】。文章转载请联系作者。
评论