Splitties 学习笔记:AlertDialog

356 阅读1分钟

一般写法,通过 Builder 链式方法调用构建:

        AlertDialog.Builder(context)
            .setTitle("title")
            .setMessage("message")
            .setPositiveButton(android.R.string.ok) { _, _ -> Log.d(TAG, "onPositiveButton: ") }
            .setNegativeButton(android.R.string.cancel) { _, _ -> Log.d(TAG, "onNegativeButton: ") }
            .setOnDismissListener { Log.d(TAG, "onDismissListener: ") }
            .create()
            .apply { setOnShowListener { Log.d(TAG, "onShowListener: ") } }
            .show()

代码块配置写法,通过 apply 调用包裹 Builder 上下文省略部分链式调用:

        AlertDialog.Builder(context).apply {
            setTitle("title")
            setMessage("message")
            setPositiveButton(android.R.string.ok) { _, _ -> Log.d(TAG, "oPositiveButton: ") }
            setNegativeButton(android.R.string.cancel) { _, _ -> Log.d(TAG, "oNegativeButton: ") }
            setOnDismissListener { Log.d(TAG, "onDismissListener: ") }
        }.create().apply { setOnShowListener { Log.d(TAG, "onShowListener: ") } }.show()

Splitties 写法:

        context.alertDialog {
            title = "title"
            message = "message"
            okButton { Log.d(TAG, "okButton: ") }
            cancelButton { Log.d(TAG, "cancelButton: ") }
            onDismiss { Log.d(TAG, "onDismiss: ") }
        }.onShow { Log.d(TAG, "onShow: ") }.show()

可以看出 Splitties 通过属性赋值的形式进行配置,更符合配置书写的一般直觉

接下来再看看实现方法

        inline fun Context.alertDialog(
            dialogConfig: AlertDialog.Builder.() -> Unit
        ): AlertDialog {
            return AlertDialog.Builder(this)
                .apply(dialogConfig)
                .create()
        }

方法参数 dialogConfig 的类型为 AlertDialog.Builder.() -> Unit ,即具体配置代码块是包裹在 AlertDialog.Builder 上下文中,但 Builder 类内并无相关配置的属性字段,那么 title message 这些属性字段又是怎么回事呢?

        var AlertDialog.Builder.title: CharSequence?
            @Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetter
            set(value) {
                setTitle(value)
            }

        internal inline val noGetter: Nothing
            get() = throw UnsupportedOperationException(NO_GETTER)

        internal const val NO_GETTER = "Property does not have a getter"

原来相关配置的属性字段也都是拓展字段,通过自定义访问器屏蔽 getter 的同时将赋值 setter 代理给 Builder 的相关方法。这种实现非常精妙,提供了一种实现拓展属性与原有方法搭建桥梁的思路