Android设计模式实战 ,实现一个弹窗引擎封装

使用设计模式封装一个弹窗引擎

前言

最近项目使用的一个第三方库很多线上 Bug 所以考虑换一个第三方库了,结果去除依赖之后导致基本每个页面都要修改,项目全部爆红,人都麻了,悔不该当初图方便没有使用引擎类啊。

第三方库提供基本的各种功能,引擎类封装一层给自己的项目预定特定的效果,上层应用只需要调用引擎即可实现效果,不需要关心底层的实现,不需要引用第三方的依赖和类库。当我们第三方库升级或替换的时候,只需要修改引擎类即可。

下面我以弹窗库的封装为例,封装一个弹窗引擎库,下来就一起来看看吧。

一、工厂模式实现不同弹窗布局的创建

其实作为一上层应用,我只关心弹窗的类型,方向,动画,是否居中,依附在哪,简单生命周期回调,控制展示和关闭即可。

以本文的第三方库 [Xpopup] 为例。它的 Api 是很多的各种方法,但是我们项目UI风格固定,只用得到那么几种。当然你完全可以换成自己的封装库或者Android原生的Dialog,WindowPoppup 都可以。

我们以常用的 底部弹窗,居中弹窗,局部下拉选,全屏下拉选,全屏弹窗这五种弹窗类型,由于传递进来一个布局我不知道是哪一种类型,所以根据弹窗类型我们要动态的返回对应的布局。

所以我们以工厂模式来创建对应的实例。

interface IPopupViewCreator<VB : ViewBinding> {
   
   
    fun create(viewBinding: ((LayoutInflater) -> VB)?): BasePopupView
}

那么基本的五种类型弹窗的创建器如下:

默认下拉选弹窗:

private open class OpenAttachPopupView<VB : ViewBinding>(
    context: Context,
    private val viewBinding: ((LayoutInflater) -> VB)?,
    private val width: Int,
    private val height: Int,
    private val maxWidth: Int,
    private val maxHeight: Int,
    private val onCreateListener: ((VB, IPopupController) -> Unit)?,
    private val onDismissListener: (() -> Unit)?,
) : AttachPopupView(context) {
   
   

    //弹窗控制器-常见的功能
    private val closeControl = IPopupController {
   
    dismiss() }
    lateinit var mBinding: VB

    override fun addInnerContent() {
   
   
        if (viewBinding != null) {
   
   
            mBinding = viewBinding.invoke(LayoutInflater.from(context))
            attachPopupContainer.addView(mBinding.root)
        } else {
   
   
            super.addInnerContent()
        }
    }

    override fun getPopupWidth(): Int {
   
   
        return if (width != 0) width else super.getPopupWidth()
    }

    override fun getPopupHeight(): Int {
   
   
        return if (height != 0) height else super.getPopupHeight()
    }

    // 如果需要覆写 getMaxWidth 和 getMaxHeight,可以提供自定义的最大宽高
    override fun getMaxWidth(): Int {
   
   
        return if (maxWidth != 0) maxWidth else super.getMaxWidth()
    }

    override fun getMaxHeight(): Int {
   
   
        return if (maxHeight != 0) maxHeight else super.getMaxHeight()
    }

    override fun onCreate() {
   
   
        super.onCreate()
        onCreateListener?.invoke(mBinding, closeControl)
    }

    override fun onDismiss() {
   
   
        super.onDismiss()
        onDismissListener?.invoke()
    }

}

class AttachPopupViewCreator<VB : ViewBinding>(
    private val context: Context,
    private val width: Int,
    private val height: Int,
    private val maxWidth: Int,
    private val maxHeight: Int,
    private val onCreateListener: ((VB, IPopupController) -> Unit)?,
    private val onDismissListener: (() -> Unit)?,
) : IPopupViewCreator<VB> {
   
   

    override fun create(viewBinding: ((LayoutInflater) -> VB)?): BasePopupView {
   
   
        return OpenAttachPopupView<VB>(
            context,
            viewBinding,
            width, height,
            maxWidth, maxHeight,
            onCreateListener, onDismissListener
        )

    }

}

全屏弹窗:

private open class OpenFullScreenPopupView<VB : ViewBinding>(
    context: Context,

    private val viewBinding: ((LayoutInflater) -> VB)?,
    private val onCreateListener: ((VB, IPopupController) -> Unit)?,
    private val onDismissListener: (() -> Unit)?,
) : FullScreenPopupView(context) {
   
   

    //弹窗控制器-常见的功能
    private val closeControl = IPopupController {
   
    dismiss() }
    lateinit var mBinding: VB

    override fun addInnerContent() {
   
   
        if (viewBinding != null) {
   
   
            mBinding = viewBinding.invoke(LayoutInflater.from(context))
            fullPopupContainer.addView(mBinding.root)
        } else {
   
   
            super.addInnerContent()
        }
    }

    override fun onCreate() {
   
   
        super.onCreate()
        onCreateListener?.invoke(mBinding, closeControl)
    }

    override fun onDismiss() {
   
   
        super.onDismiss()
        onDismissListener?.invoke()
    }

}

class FullScreenPopupViewCreator<VB : ViewBinding>(
    private val context: Context,
    private val onCreateListener: ((VB, IPopupController) -> Unit)?,
    private val onDismissListener: (() -> Unit)?,
) : IPopupViewCreator<VB> {
   
   
    override fun create( viewBinding: ((LayoutInflater) -> VB)?): BasePopupView {
   
   
        return OpenFullScreenPopupView(
            context,
            viewBinding,
            onCreateListener, onDismissListener
        )
    }
}

全屏下拉选弹窗:

private open class OpenPartPopupView<VB : ViewBinding>(
    context: Context,
    private val viewBinding: ((LayoutInflater) -> VB)?,
    private val height: Int,
    private val maxHeight: Int,
    private val onCreateListener: ((VB, IPopupController) -> Unit)?,
    private val onDismissListener: (() -> Unit)?,
) : PartShadowPopupView(context) {
   
   

    //弹窗控制器-常见的功能
    private val closeControl = IPopupController {
   
    dismiss() }

    lateinit var mBinding: VB

    override fun addInnerContent() {
   
   
        if (viewBinding != null) {
   
   
            mBinding = viewBinding.invoke(LayoutInflater.from(context))
            attachPopupContainer.addView(mBinding.root)
        } else {
   
   
            super.addInnerContent()
        }
    }

    override fun getPopupHeight(): Int {
   
   
        return if (height != 0) height else super.getPopupHeight()
    }

    override fun getMaxHeight(): Int {
   
   
        return if (maxHeight != 0) maxHeight else super.getMaxHeight()
    }

    override fun onCreate() {
   
   
        super.onCreate()
        onCreateListener?.invoke(mBinding, closeControl)
    }

    override fun onDismiss() {
   
   
        super.onDismiss()
        onDismissListener
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值