简单封装一个易拓展的Dialog

news/2024/5/19 1:33:55/文章来源:https://blog.csdn.net/ming_147/article/details/128126321

Dialog,每个项目中多多少少都会用到,肯定也会有自己的一套封装逻辑,无论如何封装,都是奔着简单复用的思想,有的是深层次的封装,也就是把相关的UI效果直接封装好,暴露可以修改的属性和方法,让调用者根据实际业务,调用修改即可,当然也有简单的封装,只封装基本的功能,其UI和实际的动作,交给调用者,两种封装方式,各有利弊,前者调用者不用自己创建UI和实现相关动作,只需要简单的调用即可,但是不易于扩展,效果比较局限,想要拓展其他的效果,就不得不自己动手实现;后者扩展性强,因为只提供基本的调用方式,也就是说,你想要什么效果都行,毕竟是所有的UI和动作都是你自己来实现,优点是它,其缺点也是它。

前者的封装司空见惯,大多数的公司也都是采取的这样的封装,毕竟调用者实现起来也是很方便,这里就不详细说了,具体我们谈一下后者的封装,后者的封装虽然调用者需要自己来实现,但是扩展性是很强的。

今天的内容大致如下:

1、效果及代码具体调用。

2、如何封装一个Dialog。

3、开源地址。

4、总结及注意事项。

一、效果及代码具体调用

通过Kotlin的扩展函数,参数以类做为扩展,封装之后,调用非常的便捷,只需要传递你要的视图即可,我们先看下具体的案例,代码如下:

      showVipDialog {addLayout(R.layout.layout_dialog_custom)//传递dialog视图set {//Dialog操作,获取View及绑定数据}}

通过以上的代码,我们就实现了一个Dialog的弹出,addLayout方法传递视图,set扩展函数进行获取View和绑定数据,这样的一个简单的封装,我们就实现了Dialog的扩展操作,针对不同的Dialog样式,传递不同的xml视图即可。

1、快速使用

为了方便大家使用,目前已经上传到了远程maven,大家可以进行依赖使用,或者下载源码依赖也可以。

根项目build.gradle

allprojects {repositories {……maven { url "https://gitee.com/AbnerAndroid/almighty/raw/master" }}
}

在需要的Module下引入依赖

dependencies {……implementation "com.vip:dialog:1.0.0"
}

2、代码案例

源码下载之后,运行项目,就可以看到给大家提供的相关Demo,当然了,由于做到了可扩展,大家想实现什么样的效果都是可以的,毕竟视图都是自己传递的。

由于所有的案例都是调用开头的代码,就不一一列举了,简单的列举几个。

普通的提示框

普通的提示框,可以按照下面的代码逻辑进行调用。

showVipDialog {addLayout(R.layout.layout_dialog_custom)//添加弹出的视图set {//逻辑处理,获取view,绑定数据setDialogCancelable(false)//点击空白不消失val btnConfirm = findView<TextView>(R.id.dialog_button_confirm)//获取ViewbtnConfirm.setOnClickListener {toast("确定")dismiss()}}
}

方法一览

方法名

参数类型

概述

addLayout

int

xml视图

set

无参

逻辑处理

style

无参

dialog设置样式

setDialogCancelable

Boolean

点击空白是否消失,默认true消失,false为不消失

findView

int

控件id,泛型为控件

dismiss

无参

隐藏dialog

getDialogView

无参

获取当前View视图

DataBinding形式的提示框

DataBinding形式和普通的区别在于,不用再获取View视图,由普通的set扩展函数改为bind扩展函数,泛型为Binding,记得把xml视图进行convert to data binding layout。

showVipDialog {addLayout(R.layout.layout_dialog_custom)//添加弹出的视图bind<LayoutDialogCustomBinding> {//逻辑处理,获取view,绑定数据it.dialogButtonConfirm.setOnClickListener {toast("确定")dismiss()}}
}

方法一览

除了普通的方法调用之外,还可以调用下面的方法。

方法名参数概述

bind

无参

和set一样进行逻辑处理,泛型为ViewDataBinding

getDataBinding

无参

获取当前的DataBinding,用于更新视图

setPendingBindings

int

传递的BR,用于xml和Data数据进行绑定

具体的案例大家直接可以看源码,源码中提供了很多常见的效果,都是可以自定义实现的,具体的就不罗列了,本身没有多少难度。

确认框

输入框

底部列表

菊花加载

二、如何封装一个Dialog

这样的一个简单的Dialog如何进行封装呢?在封装之前,我们首先要明确封装思路,1、视图由调用者传递,2、逻辑操作由调用者处理,3、样式也由调用者进行设置,也就是说,我们只封装基本的dialog使用,也就是一个壳,具体的内容,统统交给调用者进行处理,有了这三个思路我们就可以进行着手封装了。

1、封装BaseDialog

封装Base的原因,在于统一管理子类,在于简化子类的代码逻辑,便于提供公共的方法让子类实现或调用,BaseDialog这里继承的是DialogFragment,最大的原因就是,容易通过生命周期回调来管理弹窗,还有对于复杂样式的弹窗,使用DialogFragment会更加方便和高效。

和之前封装Activity一样,做为一个抽象父类,子类要实现的无非就是,视图的传递和逻辑的处理,我们就可以在父类中进行定义抽象方法,Dialog一般有自己定义的样式,我们也可以定义一个初始化样式的方法。

/*** AUTHOR:AbnerMing* INTRODUCE:初始化数据*/abstract fun initData()/*** AUTHOR:AbnerMing* INTRODUCE:初始化样式*/abstract fun initStyle()/*** AUTHOR:AbnerMing* INTRODUCE:传递的视图*/abstract fun getLayoutId(): Int

除了必要实现的方法之外,我们还可以把一些公用的方法,定义到Base里,如获取View的方法,获取控件的方法等,这么做的目的,便于子类自定义实现一些效果以及减少findViewById的调用次数。

 /*** AUTHOR:AbnerMing* INTRODUCE:获取View视图*/fun <V> findView(id: Int): View {var view = mViewSparseArray[id]if (view == null) {view = mView?.findViewById(id)mViewSparseArray.put(id, view)}return view}/*** AUTHOR:AbnerMing* INTRODUCE:获取当前View视图*/fun getDialogView(): View {return mView!!}

以上只是列举了几个实现的方法,完整的代码,大家可以看源码中的BaseDialog类。

2、拓展ViewDataBinding形式Dialog

正常的普通Dialog就可以继承BaseDialog,基本就可以满足需要的,若是要和ViewDataBinding进行结合,那么就需要拓展需求了,具体的拓展也很简单,一是绑定View,二是绑定数据,完整的代码,大家可以看源码中BaseBindingDialog类。

绑定View

通过DataBindingUtil的bind方法,得到ViewDataBinding。

mBinding = DataBindingUtil.bind(getDialogView())

绑定数据

完成xml视图和数据的绑定。

  mBinding.setVariable(variableId, t)mBinding.executePendingBindings()

3、封装工具类,拓展相关功能

为了更加方便的让调用者使用,封装拓展函数是很有必要的,要不然,调用者每次都得要继承上边的两个父类,这样的代码就会增加很多,还会创建很多的类,我们需要单独的创建一个工具类,来实例化我们需要简化的功能逻辑。

提供添加xml视图的方法

很简单的一个普通方法,没什么好说的,把传递的xml,赋值给重写的getLayoutId方法即可。

   /*** AUTHOR:AbnerMing* INTRODUCE:设置layout* @param mLayoutId xml布局*/fun addLayout(mLayoutId: Int): VipDialog {this.mLayoutId = mLayoutIdreturn this}

提供普通使用和DataBinding形式使用方法

普通和DataBinding方法,这里用到了接口回调,接口的实现则在initVMData方法里,两个方法本身功能是一样的,无非就是一个是普通,一个是返回ViewDataBinding。

/*** AUTHOR:AbnerMing* INTRODUCE:初始化数据*/fun <VB : ViewDataBinding> bind(block: (bind: VB) -> Unit): VipDialog {setDataCallBackListener(object : OnDialogDataCallbackListener {override fun dataCallback() {block.invoke(getDataBinding())}})return this}/*** AUTHOR:AbnerMing* INTRODUCE:初始化数据*/fun set(block: () -> Unit): VipDialog {setDataCallBackListener(object : OnDialogDataCallbackListener {override fun dataCallback() {block.invoke()}})return this}

提供设置样式的方法

样式的设置也就是使用了接口回调。

 /*** AUTHOR:AbnerMing* INTRODUCE:设置样式*/fun style(style: () -> Unit): VipDialog {setStyleCallBackListener(object : OnStyleCallBackListener {override fun styleCallback() {style.invoke()}})return this}

提供获取ViewDataBinding的方法

这个方法的提供是便于拿到ViewDataBinding,有效的更新视图数据。

  /*** AUTHOR:AbnerMing* INTRODUCE:获取ViewDataBinding*/fun <VB : ViewDataBinding> getDataBinding(): VB {return mBinding as VB}

我们看下整体的代码,如下:

/***AUTHOR:AbnerMing*DATE:2022/11/22*INTRODUCE:实例化功能*/
class VipDialog : BaseBindingDialog<ViewDataBinding>() {companion object {fun init(): VipDialog {return VipDialog()}}private var mLayoutId = 0override fun initVMData() {mOnDialogDataCallbackListener?.dataCallback()}override fun initStyle() {mOnStyleCallBackListener?.styleCallback()}override fun getLayoutId(): Int {return mLayoutId}/*** AUTHOR:AbnerMing* INTRODUCE:获取ViewDataBinding*/fun <VB : ViewDataBinding> getDataBinding(): VB {return mBinding as VB}/*** AUTHOR:AbnerMing* INTRODUCE:设置layout* @param mLayoutId xml布局*/fun addLayout(mLayoutId: Int): VipDialog {this.mLayoutId = mLayoutIdreturn this}/*** AUTHOR:AbnerMing* INTRODUCE:初始化数据*/fun <VB : ViewDataBinding> bind(block: (bind: VB) -> Unit): VipDialog {setDataCallBackListener(object : OnDialogDataCallbackListener {override fun dataCallback() {block.invoke(getDataBinding())}})return this}/*** AUTHOR:AbnerMing* INTRODUCE:初始化数据*/fun set(block: () -> Unit): VipDialog {setDataCallBackListener(object : OnDialogDataCallbackListener {override fun dataCallback() {block.invoke()}})return this}/*** AUTHOR:AbnerMing* INTRODUCE:设置样式*/fun style(style: () -> Unit): VipDialog {setStyleCallBackListener(object : OnStyleCallBackListener {override fun styleCallback() {style.invoke()}})return this}private var mOnDialogDataCallbackListener: OnDialogDataCallbackListener? = nullprivate fun setDataCallBackListener(mOnDialogDataCallbackListener: OnDialogDataCallbackListener) {this.mOnDialogDataCallbackListener = mOnDialogDataCallbackListener}private var mOnStyleCallBackListener: OnStyleCallBackListener? = nullprivate fun setStyleCallBackListener(mOnStyleCallBackListener: OnStyleCallBackListener) {this.mOnStyleCallBackListener = mOnStyleCallBackListener}}

4、封装拓展函数,简化调用

dialog的弹出可能有很多场景,比如Activity里,比如Fragment里,比如一个工具类中,我们可以根据已知的场景,来定义我们的调用方式,目前,我定义了两种,在Activity或者Fragment里可以直接进行调用,也就是开头的调用方式,当然了,大家也可以自己拓展。

/*** AUTHOR:AbnerMing* INTRODUCE:Activity显示Dialog*/
fun AppCompatActivity.showVipDialog(vipDialog: VipDialog.() -> Unit): VipDialog {val dialog = VipDialog.init()dialog.apply(vipDialog)setActivityDialog(this.supportFragmentManager, dialog)return dialog
}/*** AUTHOR:AbnerMing* INTRODUCE:Fragment显示Dialog*/
fun Fragment.showVipDialog(vipDialog: VipDialog.() -> Unit): VipDialog {val dialog = VipDialog.init()dialog.apply(vipDialog)setActivityDialog(this.childFragmentManager, dialog)return dialog
}

通过以上几步,我们就可以实现开头的简单调用,具体的大家可以查看相关源码。

三、开源地址

项目地址:https://github.com/AbnerMing888/VipDialog

四、总结及注意事项

在开头已经阐述,这种方式易于拓展,但是代码量相对比较多,毕竟所有的UI和逻辑都必须独自来处理,在项目中的解决方式为,如果很多的弹框效果一样,建议再封装一层,抽取公共的工具类。

还有一个需要注意的,本身扩展函数showVipDialog返回的就是调用的类,也就是一个Dialog,大家可以直接获取变量,在其他的地方做更新Dialog或者销毁的操作。

val dialog=showVipDialog {……      
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_228444.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

带你学习不一样的数据仓库系列-框架概念

编者按&#xff1a;本系列文章参考总结自IBM,FaceBook&#xff0c;Google等数据仓库构建英文文章&#xff0c;部分章节为直译过来&#xff0c;部分内容加上乐哥6年陌陌&#xff0c;快手等工作经验总结而来&#xff0c;让大家了解真实国外大厂数仓构建之路&#xff0c;国外同行对…

RabbitMQ初步到精通-第十一章-RabbitMQ之常见问题汇总

目录 RabbitMQ之常见问题汇总 1.rabbitmq丢消息场景 1.1 消息未持久化丢失 1.2 消费时消息丢失 1.3 如何阻止消息丢失 2. mq消费消息是pull 还是 push 2.1 pull形式消费 2.2 push形式消费 3. mq重复消费场景 3.1 生产端重复情况 3.2 消费端重复 3.3 如何防止 4.pre…

今年十八,喜欢ctf-web

前言 &#x1f340;作者简介&#xff1a;被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 &#x1f341;个人主页&#xff1a;红中 &#x1fad2;每日emo&#xff1a;等我把脸皮磨厚 &#x1f342;专栏地址&#xff1a;网安专栏 本来想早点睡&…

抓包工具简单介绍和 fiddler 安装

目录 1、 抓包工具介绍 2、原理 3、fiddler 安装 1、 抓包工具介绍 抓包工具&#xff0c;是个特殊的软件&#xff0c;相当于一个 “代理程序”&#xff0c;浏览器给服务器发的请求就会经过这个代理程序&#xff0c;进一步的就能分析出请求和响应的结果如何。 通俗的讲&…

【附源码】计算机毕业设计JAVA重工教师职称管理系统

【附源码】计算机毕业设计JAVA重工教师职称管理系统 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA…

【Pandas数据处理100例】(九十四):Pandas使用any()判断DataFrame中是否有True

前言 大家好,我是阿光。 本专栏整理了《Pandas数据分析处理》,内包含了各种常见的数据处理,以及Pandas内置函数的使用方法,帮助我们快速便捷的处理表格数据。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10语言环境:python3.7编译器:PyCharmPandas版本:1.3.5N…

Kotlin高仿微信-第26篇-朋友圈-选择图片、小视频对话框

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

基于ARM的环境参数检测系统设计(Labview+STM32+ZigBee)

目 录 1 绪论 1 1.1 研究背景和意义 1 1.2 研究现状 2 1.3 研究内容 3 2 系统概述和相关原理 4 2.1 系统的功能分析与设计 4 2.2 LabVIEW介绍 5 2.3 ZigBee技术 5 2.3.1 ZigBee技术概述 5 2.3.2 ZigBee网络协议 6 2.3.3 ZigBee网络拓扑结构 7 2.4 GSM技术 8 2.5 本章小结 8 3 …

[附源码]计算机毕业设计springboot企业售后服务管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

聚焦出海 长城汽车50多国家和地区经销商集团齐聚泰国车博会

11月30日&#xff0c;长城汽车携新能源豪华阵容登陆第39届泰国国际汽车博览会&#xff08;简称“泰国车博会”&#xff09;。以“GWM Light the Future”&#xff08;长城汽车点亮未来&#xff09;为参展主题&#xff0c;长城汽车旗下中大型商务豪华SUV坦克500 HEV量产版、欧拉…

pytest + yaml 框架 - 3.全局仅登录一次,在用例中自动在请求头部添加Authentication token认证

前言 我们在使用自动化测试框架的时候&#xff0c;经常会遇到一个需求&#xff0c;希望在全局用例中&#xff0c;仅登录一次&#xff0c;后续所有的用例自动带上请求头部token 或者cookies。 环境准备 Python 3.8版本 Pytest 7.2.0 最新版 pip 安装插件 pip install pytes…

iOS开发之打包上传到App Store——(一)各种证书的理解

OK&#xff0c;有日子没写iOS开发的相关文章啦&#xff0c;主要是最近的精力都没在这上面&#xff0c;不过既然产品已经快要出来了&#xff0c;就有必要了解一下各种证书啥的&#xff08;众所周知iOS的一堆证书可是很让人头大呀&#xff09;&#xff0c;最近确实被这个搞得头大…

Microsoft SQL Server 图书管理数据库的建立

文章目录题目描述创建数据库使用数据库创建三个表外码的表示形式结果展示题目描述 – 新建 “图书管理数据库" – 其中包含三个关系 – 图书&#xff08;编号&#xff0c;图书名&#xff0c;作者&#xff0c;出版社&#xff0c;类型&#xff0c;单价&#xff09; – 借阅…

Golang学习——基于vscode安装go环境

环境介绍 Linux x86_64 vscode 1.63.2 部署流程 下载并部署go安装包 根据实际环境&#xff0c;直接在go官网下载相应的编译好的二进制安装包即可&#xff1a; wget https://golang.google.cn/dl/go1.19.3.linux-amd64.tar.gz下载完成后解压安装包&#xff0c;然后将压缩包…

空域图像增强-图像灰度变换

1.图像灰度变换。自选一张图片&#xff0c;完成以下图像处理&#xff1a;①显示图像的灰度直方图&#xff1b;②直方图均衡化&#xff0c;对比变化前后的图像和灰度直方图&#xff1b;③对图像进行线性灰度变换&#xff0c;对某部分灰度值进行扩展&#xff0c;压缩其它灰度值区…

【发表案例】智能物联网类SCIEI,仅25天录用,计算机领域必投SCI快刊,12月截稿

【期刊简介】3.5-4.0&#xff0c;JCR2区&#xff0c;中科院3区 【检索情况】SCI&EI双检&#xff0c;正刊 【征稿领域】基于人工智能的工业物联网智能传感器 【参考周期】3个月左右 【截稿日期】2022年12月30日 【期刊简介】2.0-3.0&#xff0c;JCR3区&#xff0c;中科院…

unable to find valid certification path to requested target

调用https接口时出现该异常&#xff0c; Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 原因是可以看上图…

介绍一款特别好用的java反编译工具jd-gui

目录 写在前面 开始 写在前面 之前用过另一款java反编译工具jad 但是这个工具有个问题就是对于一些java8的新特性&#xff0c;比如lambda表达式是解析不出来的&#xff0c;更不用说java9和java17了。关于这款工具的使用方法就不再这里赘述了&#xff0c;如果你感兴趣可以在网…

8个关于 Promise.then 和 Promise.catch 的面试题,一定要掌握

前面&#xff0c;我们要讨论了 Promise 在异步编程中的执行&#xff0c;错过的朋友可以直接点击《10 个 JavaScript Promise 的面试题》这篇文章进行查看。 在今天的文章中&#xff0c;我们将讨论这些核心 API 用于 Promise 对象的用法。 这里我提供了10个代码片段&#xff0…

代码文档

为您的团队和您未来的自己代码文档。 Intuition 代码告诉你_怎么_做&#xff0c;注释告诉你_为什么_。——杰夫阿特伍德 可以通过代码文档来进一步组织代码&#xff0c;让其他人&#xff08;以及未来的自己&#xff09;更容易轻松地导航和扩展它。在完成编写代码库的那一刻就最…