简单封装一个易拓展的Dialog

news2025/1/10 19:05:59

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)//获取View
        btnConfirm.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 = mLayoutId
        return 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 = 0

    override 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 = mLayoutId
        return 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? = null
    private fun setDataCallBackListener(mOnDialogDataCallbackListener: OnDialogDataCallbackListener) {
        this.mOnDialogDataCallbackListener = mOnDialogDataCallbackListener
    }

    private var mOnStyleCallBackListener: OnStyleCallBackListener? = null
    private 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.coloradmin.cn/o/50562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL】数据库备份与容灾详解(实战篇)(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

优质短视频的10个共同点,戳中两个就能提高爆款几率!

优质短视频的10个共同点&#xff0c;戳中两个就能提高爆款几率&#xff01; 01、引起共鸣和认同 : 观念、遭遇和经历 昨天随便搞了一个表情&#xff0c;配了一段核酸是辛酸的文案&#xff0c;30w播放。这就是共鸣。 02、引起好奇 :为什么、什么、何时、惊喜 ; 疑问或者悬疑式…

unity webgl开发踩坑——从开发、发布到优化

目录前言unity webgl的一些注意点videoplayer修改text修改——解决不能显示汉字问题制作、读取ab包unity audioclip减小建议减小包体 全过程记录webgl的buildwebgl部署到本地、云&#xff08;IIS&#xff09;webgl部署云如何提升加载速度总结参考前言 又是一个阳光明媚的早上&…

双十二买什么牌子电容笔?值得买的平价电容笔推荐

随着网络的迅速发展&#xff0c;人们开始使用移动电话、平板、笔记本电脑等。所以&#xff0c;在我们的日常生活中&#xff0c;电容笔的使用也日益频繁。我想&#xff0c;如果只把电容笔用在日常学习、记录或者其它一些简单的事情上&#xff0c;我们就不必再去买一支价格如此昂…

mp3转wav怎么转?

mp3可谓是被人们熟知的一种音频格式了&#xff0c;早在十几年前就出了一种很流行的音乐播放器&#xff0c;叫做mp3&#xff0c;其实是这种比播放设备只能播mp3格式的音频文件而已&#xff0c;所以俗称叫做mp3。这个就足以说明了mp3格式的音频文件应用的广泛性和普及性。mp3之所…

智云通CRM:CRM数据库在经营客户中有什么作用?

CRM客户数据库是信息的存储中心&#xff0c;由一条条记录构成&#xff0c;记载着相互联系的一组信息&#xff0c;数据库是面向主题的、集成的、相对稳定的、与时间相关的数据集合&#xff0c;能够及时反映市场的实际状况&#xff0c;是企业掌握市场的重要途径。 CRM客户数据库…

[附源码]计算机毕业设计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…

[附源码]计算机毕业设计JAVA闲置物品交易管理系统

[附源码]计算机毕业设计JAVA闲置物品交易管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM my…

spring-boot-starter-data-redis 引发的一系列惨案

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> pom 引入jar包 &#xff0c;如果redis配置文件使用 lettuce &#xff0c;还需要引入 commons-pool2 &a…

iwebsec靶场 SQL注入漏洞通关笔记11-16进制编码绕过

系列文章目录 iwebsec靶场 SQL注入漏洞通关笔记1- 数字型注入_mooyuan的博客-CSDN博客 iwebsec靶场 SQL注入漏洞通关笔记2- 字符型注入&#xff08;宽字节注入&#xff09;_mooyuan的博客-CSDN博客 iwebsec靶场 SQL注入漏洞通关笔记3- bool注入&#xff08;布尔型盲注&#…

【从零开始学微服务】06.微服务架构的建设思路

大家好&#xff0c;欢迎来到万猫学社&#xff0c;跟我一起学&#xff0c;你也能成为微服务专家。 微服务看起来很美&#xff0c;但其实是需要一个技术体系或平台体系来支撑并且落地的。微服务架构建设分为两种思路&#xff1a; 框架模式服务网格&#xff08;Service Mesh&…

N皇后问题详解

文章目录一、题目描述二、题目解析&#xff08;1&#xff09;思考一(集合回溯)&#xff08;2&#xff09;思考二(数组深度递归)&#xff08;3&#xff09;思考三(位运算)一、题目描述 N 皇后问题是指在 n * n 的棋盘上要摆 n 个皇后&#xff0c; 要求&#xff1a;任何两个皇后…

Metabase学习教程:仪表盘-8

仪表板中的Markdown很有趣 如何在仪表板中使用Markdown以获得乐趣和有益。 开发有效仪表板通常包括为人们提供上下文&#xff0c;让他们了解计算是如何存在或为什么存在的。虽然精确的标题、描述和带标签的轴可以在很大程度上澄清可视化&#xff0c;但Metabase还允许您向仪表…

2022最新1w字MySQL索引面试题(附md文档)

小熊学Java个人网站&#xff1a;https://javaxiaobear.gitee.io/&#xff0c;每周持续更新干货&#xff0c;建议收藏&#xff01; 1、Mysql如何实现的索引机制&#xff1f; MySQL中索引分三类&#xff1a;B树索引、Hash索引、全文索引 2、InnoDB索引与MyISAM索引实现的区别是什…

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

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

window像mac一样使用快捷键(AutoHotkey + SharpKeys)

自己有win和mac两台笔记本, 每天都需要在两台电脑切换进行开发, 快捷键的差异就让人很难受(个人喜好mac快捷键, 常用的几个快捷键分布比较合理), 所以网上找来了解决方案供大家参考 我想作为一名 Mac User&#xff0c; 使用 Win 首先感到不适应的应该是快捷键的差异&#xff0c…

[附源码]Python计算机毕业设计Django的项目管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

[附源码]计算机毕业设计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…

【吴恩达机器学习笔记】八、应用机器学习的建议

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为学习吴恩达机器学习视频的同学提供的随堂笔记。 &#x1f4da;专栏简介&#xff1a;在这个专栏&#xff0c;我将整理吴恩达机器学习视频的所有内容的笔记&…

小袁博客重构V2.0版本重新发布(增加实时聊天/定时发布/权限管理/微信登录等功能)

有话说 第一代V1.0版本的博客项目&#xff0c;结构比较乱 &#xff0c;各种注入和各种校验&#xff0c;层次不分明 重构之后&#xff0c;分了七大模块 注册中心模块后台模块前台模块第三方服务模块实体类模块工具模块系统模块 降低了模块间的耦合度&#xff0c;结合Valid注…