Kotlin-简约之美-进阶篇(十七):DSL的简单应用
2020-02-28 本文已影响0人
门心叼龙
@[toc]
当接口的方法过多,而我们只需要其中一个方法时,例如TextView.addTextChangedListener,我们只需要它的onTextChanged方法时
1.原始方式
tv.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
print("文字修改为:$s")
}
})
显然,我们这里还需要空实现afterTextChanged和beforeTextChanged,有点繁琐
2. 空适配器模式
tv.addTextChangedListener(object : EmptyTextWatcher() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
print("文字修改为:$s")
}
})
这个其实很简单,就是加了个接口空实现的中间类而已,这也是我们通常的操作,但是在kotlin里面,我们还可以有下面这两种高级玩法
open class EmptyTextWatcher : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
}
3. 高阶函数方式
tv.addTextChangedListenerClosure(
onTextChanged = { charSequence, start, after, count ->
print("文字修改为:$charSequence")
}
)
这个就是加了一个内联的拓展方法addTextChangedListenerClosure,这个方法的参数都是函数
inline fun TextView.addTextChangedListenerClosure(
crossinline afterTextChanged: (Editable?) -> Unit = {},
crossinline beforeTextChanged: (CharSequence?, Int, Int, Int) -> Unit = { charSequence, start, count, after -> },
crossinline onTextChanged: (CharSequence?, Int, Int, Int) -> Unit = { charSequence, start, after, count -> }
) {
val listener = object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
afterTextChanged.invoke(s)
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
beforeTextChanged.invoke(s, start, count, after)
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onTextChanged.invoke(s, start, before, count)
}
}
this.addTextChangedListener(listener)
}
4. DSL方式
tv.addTextChangedListenerDsl {
onTextChanged { charSequence, start, after, count ->
print("文字修改为:$charSequence")
}
}
这个呢,就是先通过拓展方法传入方法体init,在init方法里面,初始化afterTextChanged等函数,然后在回调的方法里面调用保存的函数
fun TextView.addTextChangedListenerDsl(init: TextChangedListenerDsl.() -> Unit) {
val listener = TextChangedListenerDsl()
listener.init()
this.addTextChangedListener(listener)
}
class TextChangedListenerDsl : TextWatcher {
var afterTextChanged: ((Editable?) -> Unit)? = null
var beforeTextChanged: ((CharSequence?, Int, Int, Int) -> Unit)? = null
var onTextChanged: ((CharSequence?, Int, Int, Int) -> Unit)? = null
/**
* DSL方法
*/
fun afterTextChanged(method: (Editable?) -> Unit) {
afterTextChanged = method
}
fun beforeTextChanged(method: (CharSequence?, Int, Int, Int) -> Unit) {
beforeTextChanged = method
}
fun onTextChanged(method: (CharSequence?, Int, Int, Int) -> Unit) {
onTextChanged = method
}
/**
* 原始方法
*/
override fun afterTextChanged(s: Editable?) {
afterTextChanged?.invoke(s)
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
beforeTextChanged?.invoke(s, start, count, after)
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onTextChanged?.invoke(s, start, before, count)
}
}
以上只是DSL的一个简单示例,主要是示范怎么写DSL,如果你有更好的使用DSL的场景,欢迎补充。