How to avoid multiple button click at same time in android?

前端 未结 12 1849
太阳男子
太阳男子 2020-12-02 09:05

I\'m using two button in view. While clicking two button simultaneously it will goes to different activity at a time. How to avoid this?

I have tried like this, But

相关标签:
12条回答
  • 2020-12-02 09:40

    you can disable the multi-touch on your app by using this android:splitMotionEvents="false" and android:windowEnableSplitTouch="false" in your theme.

    <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
        ...
        <item name="android:splitMotionEvents">false</item>
        <item name="android:windowEnableSplitTouch">false</item>
    </style>
    
    0 讨论(0)
  • 2020-12-02 09:47

    Here's a class that debounce's clicks for View and MenuItem.

    import android.os.SystemClock;
    import android.support.annotation.NonNull;
    import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.View.OnClickListener;
    
    /**
     * Debounce's click events to prevent multiple rapid clicks.
     * <p/>
     * When a view is clicked, that view and any other views that have applied {@link #shareDebounce} to them,
     * will have subsequent clicks ignored for the set {@link #DEBOUNCE_DURATION_MILLIS duration}.
     */
    public final class ClickEvent {
        private static final long DEBOUNCE_DURATION_MILLIS = 1000L;
        private long debounceStartTime = 0;
    
        /**
         * Wraps the provided {@link OnClickListener OnClickListener} in a {@link ClickEvent}
         * that will prevent multiple rapid clicks from executing.
         * <p/>
         * Usage:
         * <pre>View.setOnClickListener(ClickEvent.debounce((OnClickListener) v -> // click listener runnable))</pre>
         */
        public static OnClickListener debounce(@NonNull OnClickListener onClickListener) {
            return new ClickEvent().wrapOnClickListener(onClickListener);
        }
    
        /**
         * Wraps the provided {@link OnMenuItemClickListener OnMenuItemClickListener} in a
         * that will prevent multiple rapid clicks from executing.
         * <p/>
         * Usage:
         * <pre>MenuItem.setOnClickListener(ClickEvent.debounce((OnMenuItemClickListener) v -> // click listener runnable))</pre>
         */
        public static OnMenuItemClickListener debounce(@NonNull OnMenuItemClickListener onClickListener) {
            return new ClickEvent().wrapOnClickListener(onClickListener);
        }
    
        /**
         * Allows the debounce to be shared between views to prevent multiple rapid clicks between views.
         * <p/>
         * Usage:
         * <pre>
         *     ClickEvent clickEvent = new ClickEvent();
         *     View1.setOnClickListener(clickEvent.shareDebounce((OnClickListener) v -> // click listener runnable for View1))
         *     View2.setOnClickListener(clickEvent.shareDebounce((OnClickListener) v -> // click listener runnable for View2))
         * </pre>
         */
        public OnClickListener shareDebounce(@NonNull OnClickListener listener) {
            return wrapOnClickListener(listener);
        }
    
        /**
         * Allows the debounce to be shared between views to prevent multiple rapid clicks between views.
         * Usage:
         * <pre>
         *     ClickEvent clickEvent = new ClickEvent();
         *     MenuItem1.setOnClickListener(clickEvent.shareDebounce((OnMenuItemClickListener) v -> // click listener runnable for MenuItem1))
         *     MenuItem2.setOnClickListener(clickEvent.shareDebounce((OnMenuItemClickListener) v -> // click listener runnable for MenuItem2))
         * </pre>
         */
        public OnMenuItemClickListener shareDebounce(@NonNull OnMenuItemClickListener listener) {
            return wrapOnClickListener(listener);
        }
    
        public void setDebounceStartTime() {
            debounceStartTime = SystemClock.elapsedRealtime();
        }
    
        public boolean isThrottled() {
            return SystemClock.elapsedRealtime() - debounceStartTime < DEBOUNCE_DURATION_MILLIS;
        }
    
        private OnClickListener wrapOnClickListener(@NonNull OnClickListener onClickListener) {
            if (onClickListener instanceof OnThrottledClickListener) {
                throw new IllegalArgumentException("Can't wrap OnThrottledClickListener!");
            }
            return new OnThrottledClickListener(this, onClickListener);
        }
    
        private OnMenuItemClickListener wrapOnClickListener(@NonNull OnMenuItemClickListener onClickListener) {
            if (onClickListener instanceof OnThrottledClickListener) {
                throw new IllegalArgumentException("Can't wrap OnThrottledClickListener!");
            }
            return new OnThrottledClickListener(this, onClickListener);
        }
    
        private static class OnThrottledClickListener implements OnClickListener, OnMenuItemClickListener {
            private final ClickEvent clickEvent;
            private OnClickListener wrappedListener;
            private OnMenuItemClickListener wrappedMenuItemClickLister;
    
            OnThrottledClickListener(@NonNull ClickEvent clickEvent, @NonNull OnClickListener onClickListener) {
                this.clickEvent = clickEvent;
                this.wrappedListener = onClickListener;
            }
    
            OnThrottledClickListener(@NonNull ClickEvent clickEvent, @NonNull OnMenuItemClickListener onClickListener) {
                this.clickEvent = clickEvent;
                this.wrappedMenuItemClickLister = onClickListener;
            }
    
            @Override
            public void onClick(View v) {
                if (clickEvent.isThrottled()) {
                    return;
                }
                wrappedListener.onClick(v);
                clickEvent.setDebounceStartTime();
            }
    
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                if (clickEvent.isThrottled()) {
                    return false;
                }
                clickEvent.setDebounceStartTime();
                return wrappedMenuItemClickLister.onMenuItemClick(menuItem);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 09:48

    You can try my tiny library, it provides what exactly you want using same approach as Shivanand' solution. https://github.com/RexLKW/SClick

    0 讨论(0)
  • 2020-12-02 09:49

    Cheap Solution:

    You don’t have a correct separation of concerns (MVP or any flavor) so you put your code in your Activity/Fragment

    • If you can’t handle this the correct way, at least do not use non-deterministic solutions (like a timer).

    • Use the tools you already have, say you have this code:


    //Somewhere in your onCreate()
    Button myButton = findViewById… 
    myButton.setOnClickListener(this);
    
    // Down below…
    @Override
    public void onClick(View view) {
         if (myButton.isEnabled()) {
            myButton.setEnabled(false);
            // Now do something like…
            startActivity(…);
        }
    }
    

    Now… in a completely different place in your logic, like… for example, your onCreate or your onResume or anywhere where you know you want your button working again…

     myButton.setEnabled(true);
    

    “More Modern” Approach:

    1. Do the same, but put the logic in your Presenter.
    2. Your presenter will decide if the “button” action has been triggered.
    3. Your presenter will tell its “view”: enableMyButton(); or disableMyButton() depending.
    4. Your View will do the right thing.
    5. you know… basic separation of concerns.

    WHY “enabled(true/false)”?

    Because it’s built in. Because the button will respect its state (and if you have a correct state list, it will change appearance for you, and because it will always be what you expect). Also, because it’s easier to test a presenter full of mocks, than a full activity that can grow forever in code.

    0 讨论(0)
  • 2020-12-02 09:49

    for any one using data-binding :

    @BindingAdapter("onClickWithDebounce")
    fun onClickWithDebounce(view: View, listener: android.view.View.OnClickListener) {
        view.setClickWithDebounce {
            listener.onClick(view)
        }
    }
    
    object LastClickTimeSingleton {
        var lastClickTime: Long = 0
    }
    
    fun View.setClickWithDebounce(action: () -> Unit) {
        setOnClickListener(object : View.OnClickListener {
    
            override fun onClick(v: View) {
                if (SystemClock.elapsedRealtime() - LastClickTimeSingleton.lastClickTime < 500L) return
                else action()
                LastClickTimeSingleton.lastClickTime = SystemClock.elapsedRealtime()
            }
        })
    }
    
    
    
    <androidx.appcompat.widget.AppCompatButton
                        ..
      android:text="@string/signup_signin"
      app:onClickWithDebounce="@{() -> viewModel.onSignUpClicked()}"
                       ... />
    
    0 讨论(0)
  • 2020-12-02 09:49

    A "Better" Practice is to use the onClickListener like this ->

    OnClickListener switchableListener = new OnClickListener(@Override
        public void onClick(View arg0) {
            arg0.setOnClickListener(null);
    
            (or) use the view directly as a final variable in case of errors
                 ex :
                         textView.setOnClickListener(null);
    
    
             // Some processing done here
    
             Completed , enable the onclicklistener arg0.setOnClickListener(switchableListener);
        });
    

    This should fix the problem and its quite a simple way of handling things

    0 讨论(0)
提交回复
热议问题