Two kinds of schemes

  • NoShakeClickListener implements View.onClickListener

  • NoShakeClickListener2 not implements Viet.onClickListener

Intrusive anti-shake processing (NoShakeClickListener)

1. Both apply to a singleViewEvent stabilization also appliesAdapterIn theItemViewEvents offer

2. If the event jumps to a new oneActivitytheActivityThe startup model should beandroid:launchMode="singleTop"

Java version

public abstract class NoShakeClickListener implements View.OnClickListener {

    private long mTimeInterval = 500L;
    /** * last click time */
    private long mLastClickTime;
    /** * The last clicked control ID */
    private int mLastClickViewId;

    public NoShakeClickListener(a) {}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 a quick click on **@paramV Click the control *@paramInterval Time interval (ms) *@returnTrue: 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 events
            return true;
        } else {
            // Single click events
            mLastClickTime = nowTime;
            mLastClickViewId = viewId;
            return false; }}protected void onFastClick(View v) {}
    protected abstract void onSingleClick(View v);
}
Copy the code

Can be abbreviated to

public abstract class NoShakeListener implements OnClickListener {
    private long mLastClickTime = 0;
    private boolean isFastDoubleClick(a) {
        long nowTime = System.currentTimeMillis();
        if (Math.abs(nowTime - mLastClickTime) < 500) {
            return true; // Quick click events
        } else {
            mLastClickTime = nowTime;
            return false; // Single click events}}@Override
    public void onClick(View v) {
        if (isFastDoubleClick()) {
            onFastClick(v);
        } else{ onSingleClick(v); }}protected void onFastClick(View v) {}protected abstract void onSingleClick(View v);
}
Copy the code

Kotlin version

abstract class NoShakeClickListener @JvmOverloads constructor(interval: Long = 500L) : View.OnClickListener {

    private var mTimeInterval = 500L
    private var mLastClickTime: Long = 0   // The time of the last click
    private var mLastClickViewId = 0       // ID of the control that was last clicked

    init {
        mTimeInterval = interval
    }

    override fun onClick(v: View) {
        if (isFastDoubleClick(v, mTimeInterval)) onFastClick(v) else onSingleClick(v)
    }

    /** * is a quick click on **@paramV Click the control *@paramInterval Time interval (ms) *@returnTrue: 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 events
            true
        } else {
            // Single click events
            mLastClickTime = nowTime
            mLastClickViewId = viewId
            false}}protected open fun onFastClick(v: View?). {}
    protected abstract fun onSingleClick(v: View?).
}
Copy the code

Almost forgot… Corresponding extension functions:

funView? .noShake(block: (v: View?). ->Unit) {
    this? .apply { setOnClickListener(object : NoShakeClickListener() {
            override fun onSingleClick(v: View?). {
                block.invoke(v)
            }
        })
    }
}
Copy the code

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(a) {}
            override fun onNext(o: Any) {
                listener()
            }
        })
Copy the code

Non-invasive anti-shake treatment (NoShakeClickListener2)

Features:

1. Remove the dependency on view. OnClickListener and continue to handle event stabilization without destroying the OnClickListener set by the original code;

2 supports simple handling of events and generic callbacks

/** ** event stabilization * Note: this applies not only to View, but also to other controls such as MenuItem. It applies to both a single 'View' event and an 'ItemView' event in 'Adapter'. If the event is to jump to a new 'Activity', the 'Activity' launch model should be 'Android :launchMode="singleTop" */
open class NoShakeClickListener2 @JvmOverloads constructor(interval: Long = 500L) {

    private var mTimeInterval = 500L
    private var mLastClickTime: Long = 0   // The time of the last click
    private var mLastClick: Any? = null    // The last click on the View or MenuItem...

    init {
        mTimeInterval = interval
    }

    fun proceedClick(a) {
        if (isFastClick(null, mTimeInterval)) onFastClick(null) else onSingleClick(null)}fun <T> proceedClick(item: T?). {
        if (isFastClick(item, mTimeInterval)) onFastClick(item) else onSingleClick(item)
    }

    /** * is a quick click on **@paramItem Click control View or MenuItem... *@paramInterval Time interval (ms) *@returnTrue: 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 events
            true
        } else {
            // Single click events
            mLastClickTime = nowTime
            mLastClick = item
            false}}protected open fun onFastClick(item: Any?). {}
    protected open fun onSingleClick(item: Any?).{}}Copy the code

A practical case

1 Simple Use

// Quick click events
val fastClick=object :NoShakeClickListener2(){
    override fun onFastClick(item: Any?). {
        super.onFastClick(item)
        // item == null
        Log.e("123"."onFastClick Click")
    }
}
BottomNavigationView.setOnNavigationItemSelectedListener {
    switchPage(it.itemId)
    fastClick.proceedClick()
    true
}
Copy the code

2 Send back parameters

// Quick click events
val fastClick=object :NoShakeClickListener2(){
    override fun onFastClick(item: Any?). {
        super.onFastClick(item)
        // item == null proceedClick(it)
        Log.e("123"."onFastClick Click")
    }
}
BottomNavigationView.setOnNavigationItemSelectedListener {
    switchPage(it.itemId)
    fastClick.proceedClick(it)
    true
}
Copy the code

April 20, 2021 10:39:35 simplest usage

private abstract static class NoShakeListener implements OnClickListener {
   private long mLastClickTime = 0;

   private boolean isFastDoubleClick(a) {
       long nowTime = System.currentTimeMillis();
       if (Math.abs(nowTime - mLastClickTime) < 500) {
           return true; // Quick click events
       } else {
           mLastClickTime = nowTime;
           return false; // Single click events}}@Override
   public void onClick(View v) {
       if (isFastDoubleClick()) {
           onFastClick(v);
       } else{ onSingleClick(v); }}protected void onFastClick(View v) {}protected abstract void onSingleClick(View v);
}
Copy the code