Android предотвращает двойной щелчок по кнопке - PullRequest
138 голосов
/ 10 апреля 2011

Каков наилучший способ предотвращения двойного щелчка по кнопке в Android?

Ответы [ 39 ]

297 голосов
/ 13 мая 2013

сохранение последнего щелчка при нажатии предотвратит эту проблему.

т.е.

private long mLastClickTime = 0;

...

// inside onCreate or so:

findViewById(R.id.button).setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // mis-clicking prevention, using threshold of 1000 ms
        if (SystemClock.elapsedRealtime() - mLastClickTime < 1000){
            return;
        }
        mLastClickTime = SystemClock.elapsedRealtime();

        // do your magic here
    }
}
68 голосов
/ 10 апреля 2011

Отключите кнопку с помощью setEnabled(false), пока пользователь не сможет снова нажать ее.

41 голосов
/ 19 декабря 2013

Мое решение

package com.shuai.view;

import android.os.SystemClock;
import android.view.View;

/**
 * 处理快速在某个控件上双击2次(或多次)会导致onClick被触发2次(或多次)的问题
 * 通过判断2次click事件的时间间隔进行过滤
 * 
 * 子类通过实现{@link #onSingleClick}响应click事件
 */
public abstract class OnSingleClickListener implements View.OnClickListener {
    /**
     * 最短click事件的时间间隔
     */
    private static final long MIN_CLICK_INTERVAL=600;
    /**
     * 上次click的时间
     */
    private long mLastClickTime;

    /**
     * click响应函数
     * @param v The view that was clicked.
     */
    public abstract void onSingleClick(View v);

    @Override
    public final void onClick(View v) {
        long currentClickTime=SystemClock.uptimeMillis();
        long elapsedTime=currentClickTime-mLastClickTime;
        //有可能2次连击,也有可能3连击,保证mLastClickTime记录的总是上次click的时间
        mLastClickTime=currentClickTime;

        if(elapsedTime<=MIN_CLICK_INTERVAL)
            return;

        onSingleClick(v);        
    }

}

Использование аналогично OnClickListener, но вместо этого переопределяет onSingleClick ():

mTextView.setOnClickListener(new OnSingleClickListener() {
            @Override
            public void onSingleClick(View v) {
                if (DEBUG)
                    Log.i("TAG", "onclick!");
            }
     };
40 голосов
/ 31 марта 2012

Отключение кнопки или настройка unclickable не достаточно, если вы выполняете интенсивную вычислительную работу в onClick (), поскольку события щелчка могут быть поставлены в очередь, прежде чем кнопка может быть отключена. Я написал абстрактный базовый класс, который реализует OnClickListener, который вы можете вместо этого переопределить, чтобы решить эту проблему, игнорируя любые щелчки в очереди вверх:

/** 
 * This class allows a single click and prevents multiple clicks on
 * the same button in rapid succession. Setting unclickable is not enough
 * because click events may still be queued up.
 * 
 * Override onOneClick() to handle single clicks. Call reset() when you want to
 * accept another click.
 */
public abstract class OnOneOffClickListener implements OnClickListener {
    private boolean clickable = true;

    /**
     * Override onOneClick() instead.
     */
    @Override
    public final void onClick(View v) {
        if (clickable) {
            clickable = false;
            onOneClick(v);
            //reset(); // uncomment this line to reset automatically
        }
    }

    /**
     * Override this function to handle clicks.
     * reset() must be called after each click for this function to be called
     * again.
     * @param v
     */
    public abstract void onOneClick(View v);

    /**
     * Allows another click.
     */
    public void reset() {
        clickable = true;
    }
}

Использование такое же, как OnClickListener, но вместо этого переопределяет OnOneClick ():

OnOneOffClickListener clickListener = new OnOneOffClickListener() {
    @Override
    public void onOneClick(View v) {

        // Do stuff

        this.reset(); // or you can reset somewhere else with clickListener.reset();
    }
};
myButton.setOnClickListener(clickListener);
19 голосов
/ 09 января 2018

Вы можете сделать это очень причудливо, используя Функции расширения Kotlin и RxBinding

   fun View.clickWithDebounce(debounceTime: Long = 600L, action: () -> Unit): Disposable =
        RxView.clicks(this)
                .debounce(debounceTime, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { action() }

или

fun View.clickWithDebounce(debounceTime: Long = 600L, action: () -> Unit) {
    this.setOnClickListener(object : View.OnClickListener {
        private var lastClickTime: Long = 0

        override fun onClick(v: View) {
            if (SystemClock.elapsedRealtime() - lastClickTime < debounceTime) return
            else action()

            lastClickTime = SystemClock.elapsedRealtime()
        }
    })
}

, а затемпросто:

View.clickWithDebounce{ Your code }
11 голосов
/ 29 сентября 2013

Я также столкнулся с подобной проблемой, я отображал некоторые средства выбора даты и времени, где иногда он получал клик 2 раза. Я решил это этим

long TIME = 1 * 1000;
@Override
public void onClick(final View v) {
v.setEnabled(false);

    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            v.setEnabled(true);
        }
    }, TIME);
}

Вы можете изменить время в зависимости от ваших требований. Этот метод работает для меня.

8 голосов
/ 12 сентября 2012

setEnabled(false) отлично работает для меня.

Идея в том, что я пишу { setEnabled(true); } в начале и просто делаю это false при первом нажатии кнопки.

5 голосов
/ 16 декабря 2011

Фактическим решением этой проблемы является использование setEnabled (false), который отключает кнопку, и setClickable (false), который делает его таким, чтобы второй клик не мог быть получен. Я проверил это, и это кажется очень эффективным.

4 голосов
/ 16 марта 2017

в моей ситуации я использовал вид кнопок, и он слишком быстро брал клики.просто отключите кликабельный и включите его снова через несколько секунд ...

По сути, я создал класс-обертку, который оборачивает ваши представления onClickListener.Вы также можете установить пользовательскую задержку, если хотите.

public class OnClickRateLimitedDecoratedListener implements View.OnClickListener {

    private final static int CLICK_DELAY_DEFAULT = 300;
    private View.OnClickListener onClickListener;
    private int mClickDelay;


        public OnClickRateLimitedDecoratedListener(View.OnClickListener onClickListener) {
            this(onClickListener, CLICK_DELAY_DEFAULT);
        }

        //customize your own delay
        public OnClickRateLimitedDecoratedListener(View.OnClickListener onClickListener, int delay) {
            this.onClickListener = onClickListener;
            mClickDelay = delay;
        }

        @Override
        public void onClick(final View v) {
            v.setClickable(false);
            onClickListener.onClick(v);

            v.postDelayed(new Runnable() {
                @Override
                public void run() {
                    v.setClickable(true);
                }
            }, mClickDelay);
        }
    }

и позвонить ей просто сделайте это:

mMyButton.setOnClickListener(new OnClickRateLimitedDecoratedListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 doSomething();
             }
         }));

или укажите собственную задержку:

 mMyButton.setOnClickListener(new OnClickRateLimitedDecoratedListener(new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
                         doSomething();
                     }
                 },1000));

ОБНОВЛЕНИЕ: Сверх того, немного старомодно, когда RxJava настолько распространен.как уже упоминали другие, в Android мы могли бы использовать дроссель, чтобы замедлить щелчки.Вот один пример:

 RxView.clicks(myButton)
                    .throttleFirst(2000, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                    .subscribe {
                        Log.d("i got delayed clicked")
                    }
        }

вы можете использовать эту библиотеку для него: implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'

4 голосов
/ 30 ноября 2017

Я знаю, что это старый вопрос, но я делюсь лучшим решением, которое я нашел для решения этой общей проблемы

        btnSomeButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // Prevent Two Click
            Utils.preventTwoClick(view);
            // Do magic
        }
    });

И в другом файле, например Utils.java

    /**
 * Método para prevenir doble click en un elemento
 * @param view
 */
public static void preventTwoClick(final View view){
    view.setEnabled(false);
    view.postDelayed(new Runnable() {
        public void run() {
           view.setEnabled(true);
        }
    }, 500);
}
...