1. 前言
我们平时在注册Android回调的时候,通常只会用到其中的一两个方法,但却要为此实现所有的方法
比如,注册EditText
的监听
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(text: CharSequence?, start: Int, count: Int, after: Int) {
Log.i(TAG,"beforeTextChanged")
}
override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) {
Log.i(TAG,"onTextChanged:$text")
}
override fun afterTextChanged(editable: Editable?) {
Log.i(TAG,"afterTextChanged")
}
})
又比如,注册动画的监听
animator.addListener(object : Animator.AnimatorListener{
override fun onAnimationStart(animation: Animator?) {
Log.i(TAG,"onAnimationStart")
}
override fun onAnimationEnd(animation: Animator?) {
Log.i(TAG,"onAnimationEnd")
}
override fun onAnimationCancel(animation: Animator?) {
Log.i(TAG,"onAnimationCancel")
}
override fun onAnimationRepeat(animation: Animator?) {
Log.i(TAG,"onAnimationRepeat")
}
})
本文的目标就是简化这种监听,只实现自己所需要的方法。
最终效果期望是这样的 :
textView.addTextChangedListener(onTextChanged = { text, start, count, after ->
Log.i(TAG,"onTextChanged:$text")
})
或者是这样
tabLayout.addOnTabSelectedListener(
registerOnTabSelectedListener {
onTabSelected {
Log.i(TAG, "onTabSelected:${it?.position}")
}
})
2. 方法一 : Kotlin DSL
我们可以使用Kotlin DSL
的特性,来实现这个功能,我们以editText.addTextChangedListener
为例
2.1 定义方法对应的CallBack
private typealias BeforeTextChangedCallback =
(s: CharSequence?, start: Int, count: Int, after: Int) -> Unit
private typealias OnTextChangedCallback =
(s: CharSequence?, start: Int, before: Int, count: Int) -> Unit
private typealias AfterTextChangedCallback = (s: Editable?) -> Unit
typealias表示类型别名,即这里将这些CallBack
取了一个别名,方便后面使用
2.2 实现TextWatcherBuilder继承自TextWatcher
class TextWatcherBuilder : TextWatcher {
private var beforeTextChangedCallback: BeforeTextChangedCallback? = null
private var onTextChangedCallback: OnTextChangedCallback? = null
private var afterTextChangedCallback: AfterTextChangedCallback? = null
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) =
beforeTextChangedCallback?.invoke(s, start, count, after) ?: Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) =
onTextChangedCallback?.invoke(s, start, before, count) ?: Unit
override fun afterTextChanged(s: Editable?) =
afterTextChangedCallback?.invoke(s) ?: Unit
fun beforeTextChanged(callback: BeforeTextChangedCallback) {
beforeTextChangedCallback = callback
}
fun onTextChanged(callback: OnTextChangedCallback) {
onTextChangedCallback = callback
}
fun afterTextChanged(callback: AfterTextChangedCallback) {
afterTextChangedCallback = callback
}
}
2.3 实现注册方法
inline fun registerTextWatcher(function: TextWatcherBuilder.() -> Unit) =
TextWatcherBuilder().also(function)
2.4 进行使用
editText.addTextChangedListener(
registerTextWatcher {
onTextChanged { text, start, before, count ->
Log.i(TAG, "当内容改变:$text")
}
})
2.5 其他的监听简化
2.5.1 TabLayout.addOnTabSelectedListener
private typealias OnTabCallback = (tab: Tab?) -> Unit
class OnTabSelectedListenerBuilder : OnTabSelectedListener {
private var onTabReselectedCallback: OnTabCallback? = null
private var onTabUnselectedCallback: OnTabCallback? = null
private var onTabSelectedCallback: OnTabCallback? = null
override fun onTabReselected(tab: Tab?) =
onTabReselectedCallback?.invoke(tab) ?: Unit
override fun onTabUnselected(tab: Tab?) =
onTabUnselectedCallback?.invoke(tab) ?: Unit
override fun onTabSelected(tab: Tab?) =
onTabSelectedCallback?.invoke(tab) ?: Unit
fun onTabReselected(callback: OnTabCallback) {
onTabReselectedCallback = callback
}
fun onTabUnselected(callback: OnTabCallback) {
onTabUnselectedCallback = callback
}
fun onTabSelected(callback: OnTabCallback) {
onTabSelectedCallback = callback
}
}
inline fun registerOnTabSelectedListener(function: OnTabSelectedListenerBuilder.() -> Unit) =
OnTabSelectedListenerBuilder().also(function)
进行使用
tabLayout.addOnTabSelectedListener(
registerOnTabSelectedListener {
onTabSelected {
Log.i(TAG, "当Tab被选中:${it?.position}")
}
})
2.5.2 Animator.addListener
private typealias AnimatorRepeatCallBack = (animation: Animator?) -> Unit
private typealias AnimatorEndCallBack = (animation: Animator?) -> Unit
private typealias AnimatorCancelCallBack = (animation: Animator?) -> Unit
private typealias AnimatorStartCallBack = (animation: Animator?) -> Unit
class AnimatorListenerBuilder : Animator.AnimatorListener {
private var animatorRepeatCallback: AnimatorRepeatCallBack? = null
private var animatorEndCallback: AnimatorEndCallBack? = null
private var animatorCancelCallBack: AnimatorCancelCallBack? = null
private var animatorStartCallBack: AnimatorStartCallBack? = null
override fun onAnimationRepeat(animation: Animator?) {
animatorRepeatCallback?.invoke(animation)
}
override fun onAnimationEnd(animation: Animator?) {
animatorEndCallback?.invoke(animation)
}
override fun onAnimationCancel(animation: Animator?) {
animatorCancelCallBack?.invoke(animation)
}
override fun onAnimationStart(animation: Animator?) {
animatorStartCallBack?.invoke(animation)
}
fun onAnimationRepeat(callback: AnimatorRepeatCallBack) {
animatorRepeatCallback = callback
}
fun onAnimationEnd(callback: AnimatorEndCallBack) {
animatorEndCallback = callback
}
fun onAnimationCancel(callback: AnimatorCancelCallBack) {
animatorCancelCallBack = callback
}
fun onAnimationStart(callback: AnimatorStartCallBack) {
animatorStartCallBack = callback
}
}
inline fun registerAnimatorListener(function: AnimatorListenerBuilder.() -> Unit) =
AnimatorListenerBuilder().also(function)
进行使用
animator.addListener(
registerAnimatorListener {
onAnimationStart {
Log.i(TAG, "animator start")
}
}
)
2.5.3 Animation.setAnimationListener
private typealias AnimationStartCallBack = (animation: Animation?) -> Unit
private typealias AnimationEndCallBack = (animation: Animation?) -> Unit
private typealias AnimationRepeatCallBack = (animation: Animation?) -> Unit
class AnimationListenerBuilder : Animation.AnimationListener {
private var animationStartCallBack: AnimationStartCallBack? = null
private var animationEndCallBack: AnimationEndCallBack? = null
private var animationRepeatCallBack: AnimationRepeatCallBack? = null
override fun onAnimationStart(animation: Animation?) {
animationStartCallBack?.invoke(animation)
}
override fun onAnimationEnd(animation: Animation?) {
animationEndCallBack?.invoke(animation)
}
override fun onAnimationRepeat(animation: Animation?) {
animationRepeatCallBack?.invoke(animation)
}
fun onAnimationStart(animation: AnimationStartCallBack) {
animationStartCallBack = animation
}
fun onAnimationEnd(animation: AnimationEndCallBack) {
animationEndCallBack = animation
}
fun onAnimationRepeat(animation: AnimationRepeatCallBack) {
animationRepeatCallBack = animation
}
}
inline fun registerAnimationListener(function: AnimationListenerBuilder.() -> Unit) =
AnimationListenerBuilder().also(function)
进行使用
animation.setAnimationListener(
registerAnimationListener {
onAnimationStart {
Log.i(TAG, "animation start")
}
}
)
3. 方法二 : Kotlin 扩展
使用Kotlin的扩展函数,我们也可以实现监听/回调的简化,这里,我们以TabLayout.addOnTabSelectedListener
为例
3.1 实现TabLayout的扩展方法
public inline fun TabLayout.addOnTabSelectedListener(
crossinline onTabSelected: (tab: TabLayout.Tab?) -> Unit = {},
crossinline onTabUnselected: (tab: TabLayout.Tab?) -> Unit = {},
crossinline onTabReselected: (tab: TabLayout.Tab?) -> Unit = {}
): TabLayout.OnTabSelectedListener {
val listener = object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
onTabSelected.invoke(tab)
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
onTabUnselected.invoke(tab)
}
override fun onTabReselected(tab: TabLayout.Tab?) {
onTabReselected.invoke(tab)
}
}
addOnTabSelectedListener(listener)
return listener
}
3.2 进行使用
tabLayout.addOnTabSelectedListener(
onTabSelected = {
Log.i(TAG,"onTabSelected:"+it?.position)
})
3.3 实现单个方法的扩展方法
我们还可以实现单个方法的扩展方法,这样使用会更简单
public inline fun TabLayout.doOnTabSelected(
crossinline onTabSelected: (tab: TabLayout.Tab?) -> Unit = {}
) = addOnTabSelectedListener(onTabSelected = {
onTabSelected.invoke(it)
})
public inline fun TabLayout.doOnTabUnselected(
crossinline onTabUnselected: (tab: TabLayout.Tab?) -> Unit = {}
) = addOnTabSelectedListener(onTabUnselected = {
onTabUnselected.invoke(it)
})
public inline fun TabLayout.doOnTabReselected(
crossinline onTabReselected: (tab: TabLayout.Tab?) -> Unit = {}
) = addOnTabSelectedListener(onTabReselected = {
onTabReselected.invoke(it)
})
3.4 进行使用
tabLayout.doOnTabSelected {
Log.i(TAG,"onTabSelected:"+it?.position)
}
3.5 Kotlin-ktx
在kotlin-ktx
中,Google
已经为我们做了一些监听的简化了,可以直接使用。
3.5.1 引入包
implementation 'androidx.core:core-ktx:1.7.0'
3.5.2 TextView中进行使用
textView.addTextChangedListener(onTextChanged = { text, start, before, count ->
Log.i(TAG,"onTextChanged:$text")
})
还可以直接注册其某一个方法
textView.doBeforeTextChanged { text, start, count, after ->
Log.i(TAG, "onBeforeTextChanged:$text")
}
textView.doOnTextChanged { text, start, before, count ->
Log.i(TAG, "onTextChange:$text")
}
textView.doAfterTextChanged {
Log.i(TAG, "onAfterTextChanged")
}
3.5.3 Animator中进行使用
val animator = ValueAnimator.ofInt(0, 100)
animator.addListener(onStart = {
Log.i(TAG,"onStart")
}, onEnd = {
Log.i(TAG,"onEnd")
}, onRepeat = {
Log.i(TAG,"onRepeat")
}, onCancel = {
Log.i(TAG,"onCancel")
})
也可以直接注册其某一个方法
animator.doOnStart {
Log.i(TAG,"onStart")
}
animator.doOnEnd {
Log.i(TAG,"onEnd")
}
animator.doOnRepeat {
Log.i(TAG,"onRepeat")
}
animator.doOnCancel {
Log.i(TAG,"onCancel")
}
3.5.4 Transition中进行使用
val startScene = Scene.getSceneForLayout(group, R.layout.activity_main_start, this)
val changeBounds = ChangeBounds()
TransitionManager.go(startScene, changeBounds)
changeBounds.addListener(
onStart = {
Log.i(TAG,"onStart")
},
onEnd = {
Log.i(TAG,"onEnd")
},
onCancel = {
Log.i(TAG,"onCancel")
},
onResume = {
Log.i(TAG,"onResume")
},
onPause = {
Log.i(TAG,"onPause")
})
也可以直接注册其某一个方法
changeBounds.doOnStart {
Log.i(TAG, "onOnStart")
}
changeBounds.doOnEnd {
Log.i(TAG, "onOnEnd")
}
changeBounds.doOnCancel {
Log.i(TAG, "onOnCancel")
}
changeBounds.doOnResume {
Log.i(TAG, "onOnResume")
}
changeBounds.doOnPause {
Log.i(TAG, "doOnPause")
}
关于 Transition 可以看我的另几篇博客
Android 使用TransitionManager来方便地实现过渡动画
Android TransitionManager源码解析
更多Android KTX
方法的介绍,可以看我的另一篇博客 Android KTX | 官方 Kotlin-core 扩展库 方法大全