callbackFlow看起来方便把回调的事件封装为流,参考其他一些资料,再动手封装如下:
import android.view.View import androidx.lifecycle.LifecycleCoroutineScope import com.chetuan.findcar2.R import kotlinx.coroutines.CancellationException import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach fun <E> SendChannel<E>.safeSend(value: E) = try { trySend(value) } catch (e: CancellationException) { e.printStackTrace() } fun View.clickFlow(): Flow<View> { return callbackFlow { setOnClickListener { safeSend(it) } awaitClose { setOnClickListener(null) } } } inline fun View.click(lifecycle: LifecycleCoroutineScope, crossinline onClick: (view: View) -> Unit) { clickFlow().onEach { onClick(this) }.launchIn(lifecycle) } /** * 延迟第一次点击事件 * * Example: * * view.clickDelayed(lifecycleScope) { * showShortToast("xxx") * } */ inline fun View.clickDelayed( lifecycle: LifecycleCoroutineScope, delayMillis: Long = 500, crossinline onClick: (view: View) -> Unit ) { clickFlow().onEach { delay(delayMillis) onClick(this) }.launchIn(lifecycle) } fun getLastMillis(v: View, id: Int): Long { return if (v.getTag(id) != null) v.getTag(id) as Long else 0L } fun setLastMillis(v: View, id: Int, millis: Long) { v.setTag(id, millis) } inline fun View.clickTrigger( lifecycle: LifecycleCoroutineScope, intervalMillis: Long = 1000, crossinline onClick: (view: View) -> Unit ) { val id = R.id.tag_pos_key clickFlow().onEach { val currentMillis = System.currentTimeMillis() if (currentMillis - getLastMillis(this, id) < intervalMillis) { return@onEach } setLastMillis(this, id, currentMillis) onClick(this) }.launchIn(lifecycle) }
在Activity/Fragment中用法如下:
binding.btnCommit.clickTrigger(lifecycleScope) { commit() }