Two schemes of Android View event anti shake
- 2021-12-12 05:32:36
- OfStack
Two options
Intrusive anti-shake treatment (NoShakeClickListener) implements View. OnClickListener
Non-invasive anti-shake treatment (NoShakeClickListener2) not implements View. OnClickListener
Invasive anti-shake treatment (NoShakeClickListener)
1. It is suitable for both single View event anti-shake and ItemView event anti-shake in Adapter
2. If the event is jump to new Activity, the Activity startup model should be android: launchMode = "singleTop"
Java version
public abstract class NoShakeClickListener implements View.OnClickListener {
private long mTimeInterval = 500L;
/**
* Recently 1 Time of the second click
*/
private long mLastClickTime;
/**
* Recently 1 The control that is clicked next time ID
*/
private int mLastClickViewId;
public NoShakeClickListener() {
}
public NoShakeClickListener(long interval) {
this.mTimeInterval = interval;
}
@Override
public void onClick(View v) {
final boolean isFastClick = isFastDoubleClick(v, this.mTimeInterval);
if (isFastClick) {
onFastClick(v);
} else {
onSingleClick(v);
}
}
/**
* Is it a quick click
*
* @param v Clicked controls
* @param interval Time interval (milliseconds)
* @return true: Yes, false: No
*/
private boolean isFastDoubleClick(View v, long interval) {
int viewId = v.getId();
long nowTime = System.currentTimeMillis();
long timeInterval = Math.abs(nowTime - mLastClickTime);
if (timeInterval < interval && viewId == mLastClickViewId) {
// Quick click event
return true;
} else {
// Single click event
mLastClickTime = nowTime;
mLastClickViewId = viewId;
return false;
}
}
protected void onFastClick(View v) {}
protected abstract void onSingleClick(View v);
}
Can be abbreviated as
public abstract class NoShakeListener implements OnClickListener {
private long mLastClickTime = 0;
private boolean isFastDoubleClick() {
long nowTime = System.currentTimeMillis();
if (Math.abs(nowTime - mLastClickTime) < 500) {
return true; // Quick click event
} else {
mLastClickTime = nowTime;
return false; // Single click event
}
}
@Override
public void onClick(View v) {
if (isFastDoubleClick()) {
onFastClick(v);
} else {
onSingleClick(v);
}
}
protected void onFastClick(View v) {
}
protected abstract void onSingleClick(View v);
}
Kotlin version
abstract class NoShakeClickListener @JvmOverloads constructor(interval: Long = 500L) : View.OnClickListener {
private var mTimeInterval = 500L
private var mLastClickTime: Long = 0 // Recently 1 Time of the second click
private var mLastClickViewId = 0 // Recently 1 The control that is clicked next time ID
init {
mTimeInterval = interval
}
override fun onClick(v: View) {
if (isFastDoubleClick(v, mTimeInterval)) onFastClick(v) else onSingleClick(v)
}
/**
* Is it a quick click
*
* @param v Clicked controls
* @param interval Time interval (milliseconds)
* @return true: Yes, false: No
*/
private fun isFastDoubleClick(v: View, interval: Long): Boolean {
val viewId = v.id
val nowTime = System.currentTimeMillis()
val timeInterval = abs(nowTime - mLastClickTime)
return if (timeInterval < interval && viewId == mLastClickViewId) {
// Quick click event
true
} else {
// Single click event
mLastClickTime = nowTime
mLastClickViewId = viewId
false
}
}
protected open fun onFastClick(v: View?) {}
protected abstract fun onSingleClick(v: View?)
}
Almost forgot... the corresponding extension function:
fun View?.noShake(block: (v: View?) -> Unit) {
this?.apply {
setOnClickListener(object : NoShakeClickListener() {
override fun onSingleClick(v: View?) {
block.invoke(v)
}
})
}
}
RxJava2 clickExt.kt
inline fun <T : View> T.noShake(crossinline listener: T.() -> Unit) = this.noShake(1000, listener)
inline fun <T : View> T.noShake(windowDuration: Long = 500, crossinline listener : T.() -> Unit) =
RxView.clicks(this)
.throttleFirst(windowDuration, TimeUnit.MILLISECONDS)
.subscribe(object : Observer<Any> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {}
override fun onComplete() {}
override fun onNext(o: Any) {
listener()
}
})
Non-invasive anti-shake treatment (NoShakeClickListener2)
Features:
1. Remove the dependence on View. OnClickListener, and continue to deal with event anti-shake without destroying the OnClickListener set in the original code;
2 supports simple handling of events and generic callbacks
/**
* Event anti-shake
* Note : Not only applies to View , Other controls such as : MenuItem Be equally applicable
*
* 1. Applicable to a single `View` Event anti-shake , It also applies to `Adapter` Medium `ItemView` Event anti-shake
* 2. If the event is to jump to a new `Activity`, The `Activity` The startup model should be `android:launchMode="singleTop"`
*/
open class NoShakeClickListener2 @JvmOverloads constructor(interval: Long = 500L) {
private var mTimeInterval = 500L
private var mLastClickTime: Long = 0 // Recently 1 Time of the second click
private var mLastClick: Any? = null // Recently 1 The control that is clicked next time View or MenuItem ...
init {
mTimeInterval = interval
}
fun proceedClick() {
if (isFastClick(null, mTimeInterval)) onFastClick(null) else onSingleClick(null)
}
fun <T> proceedClick(item: T?) {
if (isFastClick(item, mTimeInterval)) onFastClick(item) else onSingleClick(item)
}
/**
* Is it a quick click
*
* @param item Clicked controls View or MenuItem ...
* @param interval Time interval (milliseconds)
* @return true: Yes, false: No
*/
private fun <T> isFastClick(item: T?, interval: Long): Boolean {
val nowTime = System.currentTimeMillis()
val timeInterval = abs(nowTime - mLastClickTime)
return if (timeInterval < interval && item == mLastClick) {
// Quick click event
true
} else {
// Single click event
mLastClickTime = nowTime
mLastClick = item
false
}
}
protected open fun onFastClick(item: Any?) {}
protected open fun onSingleClick(item: Any?) {}
}
Practical case
1 Easy to use
// Quick click event
val fastClick=object :NoShakeClickListener2(){
override fun onFastClick(item: Any?) {
super.onFastClick(item)
// At this time item == null
Log.e("123", "onFastClick Click")
}
}
BottomNavigationView.setOnNavigationItemSelectedListener {
switchPage(it.itemId)
fastClick.proceedClick()
true
}
2 Return parameters
// Quick click event
val fastClick=object :NoShakeClickListener2(){
override fun onFastClick(item: Any?) {
super.onFastClick(item)
// At this time item == null For proceedClick(it) In it
Log.e("123", "onFastClick Click")
}
}
BottomNavigationView.setOnNavigationItemSelectedListener {
switchPage(it.itemId)
fastClick.proceedClick(it)
true
}
The above is the Android View event anti-shake two schemes detailed content, more about Android View event anti-shake information please pay attention to other related articles on this site!