Simply encapsulate an easy-to-extend Dialog

Dialog, which is more or less used in every project, will definitely have its own set of encapsulation logic. No matter how it is encapsulated, it is all about the idea of ​​simple reuse. The effect is directly encapsulated, and the properties and methods that can be modified are exposed, allowing the caller to call and modify according to the actual business. Of course, there is also a simple encapsulation, which only encapsulates the basic functions. The UI and actual actions are handed over to the caller. Each encapsulation method has its own advantages and disadvantages. The caller of the former does not need to create the UI and implement related actions by himself, but only needs a simple call, but it is not easy to expand, and the effect is relatively limited. If you want to expand other effects, you have to implement it yourself. ;The latter is highly extensible, because it only provides basic calling methods, that is to say, you can have any effect you want. After all, all UI and actions are implemented by yourself. It has advantages and disadvantages.

The former’s encapsulation is commonplace, and most companies also adopt this encapsulation. After all, it is very convenient for the caller to implement, so I won’t go into details here. Let’s talk about the latter’s encapsulation. Although the caller’s encapsulation You need to implement it yourself, but the scalability is very strong.

Today's content is roughly as follows:

1. Effect and code specific call.

2. How to encapsulate a Dialog.

3. Open source address.

4. Summary and precautions.

1. Effect and code specific call

Through Kotlin's extension function, the parameters are extended by class. After encapsulation, the call is very convenient. You only need to pass the view you want. Let's look at the specific case first. The code is as follows:

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

Through the above code, we have realized the pop-up of a Dialog, the addLayout method passes the view, and the set extension function obtains the View and binds the data. With such a simple package, we realize the extended operation of the Dialog, for different Dialogs Style, just pass different xml views.

1. Quick use

For the convenience of everyone, it has been uploaded to the remote maven, and you can use it as a dependency, or download the source code dependency.

root project build.gradle

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

Introduce dependencies under the required Module

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

2. Code case

After downloading the source code and running the project, you can see the relevant demo provided for you. Of course, because of the scalability, you can achieve any effect you want. After all, the views are passed by yourself.

Since all the cases are codes at the beginning of the call, I will not list them one by one, but simply list a few.

normal tooltip

Ordinary prompt boxes can be called according to the following code logic.

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()
        }
    }
}

List of methods

method name

Parameter Type

overview

addLayout

int

xml view

set

No reference

logic processing

style

No reference

dialog setting style

setDialogCancelable

Boolean

Click whether the blank disappears, the default is true to disappear, false is not to disappear

findView

int

Control id, the generic type is control

dismiss

No reference

hide dialog

getDialogView

No reference

Get the current View view

Prompt box in the form of DataBinding

The difference between the DataBinding form and the normal one is that you don’t need to get the View view anymore, instead of the normal set extension function to the bind extension function, the generic type is Binding, remember to convert the xml view to data binding layout.

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

List of methods

In addition to normal method calls, the following methods can also be called.

method name parameter overview

bind

No reference

Logical processing like set, the generic type is ViewDataBinding

getDataBinding

No reference

Get the current DataBinding for updating the view

setPendingBindings

int

The passed BR is used for binding xml and Data data

For specific cases, you can directly look at the source code. The source code provides many common effects, all of which can be customized and implemented.

confirmation box

Input box

bottom list

daisy loaded

2. How to encapsulate a Dialog

How to encapsulate such a simple Dialog? Before encapsulation, we must first clarify the encapsulation idea, 1. The view is passed by the caller, 2. The logic operation is processed by the caller, and 3. The style is also set by the caller. That is to say, we only encapsulate the basic dialog. It is a shell, and the specific content is all handed over to the caller for processing. With these three ideas, we can start packaging.

1. Encapsulate BaseDialog

The reason for encapsulating Base is to unify the management of subclasses, to simplify the code logic of subclasses, and to provide public methods for subclasses to implement or call. BaseDialog here inherits DialogFragment. The biggest reason is that it is easy to manage through life cycle callbacks For pop-up windows, and for complex-style pop-up windows, it will be more convenient and efficient to use DialogFragment.

Just like encapsulating Activity before, as an abstract parent class, what the subclass needs to achieve is nothing more than view transfer and logic processing. We can define abstract methods in the parent class. Dialog generally has its own defined style. We It is also possible to define a method to initialize styles.

/**
     * AUTHOR:AbnerMing
     * INTRODUCE:初始化数据
     */
    abstract fun initData()

    /**
     * AUTHOR:AbnerMing
     * INTRODUCE:初始化样式
     */
    abstract fun initStyle()

    /**
     * AUTHOR:AbnerMing
     * INTRODUCE:传递的视图
     */
    abstract fun getLayoutId(): Int

In addition to the necessary implementation methods, we can also define some common methods into Base, such as the method of obtaining View, the method of obtaining controls, etc. The purpose of this is to facilitate subclass customization to achieve some effects and reduce findViewById the number of calls.

 /**
     * 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!!
    }

The above are just a few implementation methods. For the complete code, you can see the BaseDialog class in the source code.

2. Expand ViewDataBinding form Dialog

A normal ordinary Dialog can inherit BaseDialog, which can basically meet the needs. If you want to combine it with ViewDataBinding , you need to expand the requirements. The specific expansion is also very simple. One is to bind View, and the other is to bind data. Complete For the code, you can see the BaseBindingDialog class in the source code.

bind view

Obtain ViewDataBinding through the bind method of DataBindingUtil.

mBinding = DataBindingUtil.bind(getDialogView())

bind data

Complete the binding of xml view and data.

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

3. Encapsulate tools and expand related functions

In order to be more convenient for the caller to use, it is necessary to encapsulate the extension function, otherwise, the caller has to inherit the above two parent classes every time, so the code will increase a lot, and many classes will be created , we need to create a tool class separately to instantiate the functional logic we need to simplify.

Provides a method to add xml view

It is a very simple common method, there is nothing to say, just assign the passed xml to the rewritten getLayoutId method.

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

Provide common use and DataBinding form use methods

Common and DataBinding methods, the interface callback is used here, and the implementation of the interface is in the initVMData method. The functions of the two methods are the same, nothing more than one is normal, and the other is to return 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
    }

Provides a method for setting styles

The setting of the style is to use the interface callback.

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

Provides a method to obtain ViewDataBinding

This method is provided to facilitate access to ViewDataBinding and effectively update view data.

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

Let's look at the overall code, as follows:

/**
 *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. Encapsulate extended functions to simplify calls

There may be many scenarios for dialog pop-up, such as in Activity, such as in Fragment, such as in a tool class, we can define our calling method according to known scenarios. At present, I have defined two types, in Activity or Fragment It can be called directly, which is the calling method at the beginning. Of course, you can also expand it yourself.

/**
 * 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
}

Through the above steps, we can realize the simple call at the beginning, and you can check the relevant source code for details.

3. Open source address

Project address: https://github.com/AbnerMing888/VipDialog

4. Summary and Precautions

As explained at the beginning, this method is easy to expand, but the amount of code is relatively large. After all, all UI and logic must be handled independently. The solution in the project is that if many bullet boxes have the same effect, it is recommended to encapsulate them again. Layer, extracting public tool classes.

Another thing to note is that the extended function showVipDialog itself returns the called class, that is, a Dialog. You can directly obtain variables, and update or destroy the Dialog in other places.

val dialog=showVipDialog {
         ……      
}

Guess you like

Origin blog.csdn.net/ming_147/article/details/128126321