Case scenario
When too many interface methods, but we only need one method, for example TextView.addTextChangedListener, we just need it onTextChanged method
1. Original mode
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")
}
})
Obviously, we here need to realize afterTextChanged empty and beforeTextChanged, a bit tedious
2. Empty the adapter mode
tv.addTextChangedListener(object : EmptyTextWatcher() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
print("文字修改为:$s")
}
})
This is actually very simple, is to add a middle class interface empty implementation of it, this is our normal operation, but in kotlin there, we can also have the following two high-level gameplay
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. Higher-order functions the way
tv.addTextChangedListenerClosure(
onTextChanged = { charSequence, start, after, count ->
print("文字修改为:$charSequence")
}
)
This is a method to expand the added inline addTextChangedListenerClosure, parameters are a function of this method
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 manner
tv.addTextChangedListenerDsl {
onTextChanged { charSequence, start, after, count ->
print("文字修改为:$charSequence")
}
}
This then, is the first to pass through the expansion method init method body, inside the init method, initialize afterTextChanged and other functions, and then call the Save method in the callback function inside
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)
}
}
These are just a simple example DSL, mainly DSL demonstrate how to write, if you have a better use of DSL scene, welcome to add.