一般写法,通过 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 的相关方法。这种实现非常精妙,提供了一种实现拓展属性与原有方法搭建桥梁的思路