在Android中,简化冗长的监听/回调 写法

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 扩展库 方法大全

猜你喜欢

转载自blog.csdn.net/EthanCo/article/details/127124744
今日推荐