Android 開發(fā)中點(diǎn)擊事件的處理一般是網(wǎng)絡(luò)請求、彈出提示帚呼、跳轉(zhuǎn)界面。
如果用戶快速連續(xù)點(diǎn)擊兩次皱蹦,就會請求兩次網(wǎng)絡(luò)煤杀,或是彈出兩次提示等。
為了避免這種情況的方法沪哺,需要做點(diǎn)擊事件防抖沈自,即在一定時(shí)間間隔內(nèi)只響應(yīng)第一次點(diǎn)擊事件。
方式一
利用 view 的 clickable:
inline fun View.setThrottleListener(
thresholdMillis: Long = 500L,
crossinline block: () -> Unit
) {
setOnClickListener {
isClickable = false
postDelayed({ isClickable = true }, thresholdMillis)
block.invoke()
}
}
// 使用方式
mBinding.btn.setThrottleListener {
// 處理點(diǎn)擊邏輯
}
方式二
在 view 的 tag 中記錄最后一次點(diǎn)擊時(shí)間辜妓,首先在 ids.xml 中添加:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="clickLastTimeKey" type="id" />
</resources>
var View.clickLastTime: Long
get() = getTag(R.id.clickLastTimeKey) as? Long ?: 0
set(value) = setTag(R.id.clickLastTimeKey, value)
fun View.setThrottleListener(thresholdMillis: Long = 500, block: () -> Unit) {
setOnClickListener {
val currentTime = SystemClock.elapsedRealtime()
if (currentTime - clickLastTime >= thresholdMillis) {
clickLastTime = currentTime
block.invoke()
}
}
}
// 使用
mBinding.btn.setThrottleListener {
// 處理點(diǎn)擊邏輯
}
方式三
同樣是記錄最后一次點(diǎn)擊時(shí)間枯途,不過是使用 flow:
fun <T> Flow<T>.throttleFirst(thresholdMillis: Long): Flow<T> = flow {
var lastTime = 0L
collect { upstream ->
val currentTime = SystemClock.elapsedRealtime()
if (currentTime - lastTime >= thresholdMillis) {
lastTime = currentTime
emit(upstream)
}
}
}
@ExperimentalCoroutinesApi
fun View.clickFlow() = callbackFlow {
setOnClickListener { trySend(Unit).onFailure { e -> e?.printStackTrace() } }
awaitClose { setOnClickListener(null) }
}
// 使用
mBinding.btn.clickFlow().throttleFirst(500)
.onEach {} // 處理點(diǎn)擊邏輯
.launchIn(lifecycleScope)