Android zapobiega dwukrotnemu kliknięciu przycisku

177

Jaki jest najlepszy sposób zapobiegania podwójnemu kliknięciu przycisku w systemie Android?

Androider
źródło
3
Zobacz rozwiązanie qezt, tylko w pełni działające
Gennadiy Ryabkin
3
Rozwiązanie qezt powinno zostać zaakceptowane, aby osoby odwiedzające tę stronę poznały wady korzystania z setEnabled (false).
LoveForDroid
Możesz wypróbować moją bibliotekę, korzystając z rozwiązania ostatniego kliknięcia: github.com/RexLKW/SClick
Rex Lam
1
@Androider, zmień najlepszą odpowiedź
Amir133

Odpowiedzi:

87

Wyłącz przycisk za pomocą, setEnabled(false)dopóki użytkownik nie będzie mógł go ponownie kliknąć.

CommonsWare
źródło
47
setEnabled (false) nie wydaje się działać wystarczająco szybko. Skonfigurowałem View.OnClickListener.onClick (widok) dla przycisku. Pierwszą rzeczą, którą robię w onClick (), jest napisanie instrukcji dziennika, druga instrukcja to button.setEnabled (false). Po szybkim dwukrotnym kliknięciu emulatora widzę, że instrukcja log pojawia się dwukrotnie! Nawet po dodaniu setClickable (false) bezpośrednio po tym instrukcja log pojawia się dwukrotnie.
QQQuestions
Hmmm, może kod do setEnabled (true) na końcu onClick () jest wykonywany tak szybko, że jest już ponownie włączony ...
QQQuestions
91
Miałem podobny problem. Według pewnego pomocnego dżentelmena, Android faktycznie kolejkuje kliknięcia, więc nie ma znaczenia, jak szybko lub wolno wykonuje kod onClick (); tylko jak szybko klikniesz przycisk. To znaczy. Możliwe, że już wyłączyłeś przycisk, ale kolejka kliknięć została już wypełniona dwoma lub trzema kliknięciami, a wyłączenie przycisku nie ma wpływu na dostarczanie kliknięć w kolejce. (choć może powinno?)
Nick
3
Ten rzadki moment, kiedy widzisz „kogoś”, daje dokładną odpowiedź, a nie abstraaaaaaaaktyczne odpowiedzi na zadane pytanie ..: P
Rahul
nie zawsze jest to właściwe rozwiązanie. Jeśli operacja onClick jest kosztowna, przycisk nie wyłączy się wystarczająco szybko. W pełni sprawdzonym rozwiązaniem IMHO jest użycie czasu ostatniego kliknięcia, ale także wyłączenie przycisku, aby uniknąć ponownego dotknięcia go przez użytkownika, jeśli spodziewasz się, że operacja potrwa jakiś czas (np. Logowanie).
Sarang,
368

zapisanie czasu ostatniego kliknięcia zapobiegnie temu problemowi.

to znaczy

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
    }
}
qezt
źródło
21
To jedyne rozwiązanie, które faktycznie zapobiega podwójnemu kliknięciu. Właśnie spędziłem godzinę próbując wszystkich innych, ponieważ ta metoda jest dość niezgrabna, ale żadna z nich nie mogła zapobiec szybkiemu podwójnemu dotknięciu widoku z wyjątkiem tego. Google, napraw to :)
ashishduh
6
To rozwiązanie działa dobrze, ale działa również wtedy, gdy masz wiele przycisków na ekranie i chcesz kliknąć tylko jeden przycisk naraz.
nieważne
12
Nie zapobiega to całkowicie podwójnemu kliknięciu, jeśli klikniesz dwukrotnie wystarczająco szybko.
Loc
4
Najlepsza odpowiedź, powinna być na górze
Gennadiy Ryabkin
3
To rozwiązanie powinno być właściwą odpowiedzią ... setEnabled (false) nie wystarczy.
heloisasim
55

Moje rozwiązanie to

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);        
    }

}

Użycie jest podobne do OnClickListener, ale zamiast tego zastąp onSingleClick ():

mTextView.setOnClickListener(new OnSingleClickListener() {
            @Override
            public void onSingleClick(View v) {
                if (DEBUG)
                    Log.i("TAG", "onclick!");
            }
     };
jinshiyi11
źródło
1
Łatwy i doskonały do ​​automatycznego zapobiegania podwójnemu dotknięciu.
Benjamin Piette,
1
Nie zapobiega to całkowicie podwójnemu kliknięciu, jeśli klikniesz dwukrotnie wystarczająco szybko.
Loc
1
Świetne rozwiązanie. Właśnie zmieniłem MIN_CLICK_INTERVAL = 1000;
Nizam
5
Gdybym miał wciskać dokładnie przycisk co 0,5 sekundy, żadne z moich kolejnych kliknięć nie przeszłoby, ponieważ mLastClickTime byłby aktualizowany przy każdym kliknięciu. Moją sugestią byłoby przypisanie mLastClickTime po sprawdzeniu interwału.
k2col
mLastClickTime = currentClickTime; należy umieścić po if (elapsedTime <= MIN_CLICK_INTERVAL) return;
Loyea
41

Wyłączenie przycisku lub ustawienie niemożności kliknięcia nie wystarczy, jeśli wykonujesz intensywną obliczeniowo pracę w onClick (), ponieważ zdarzenia kliknięcia mogą zostać umieszczone w kolejce przed wyłączeniem przycisku. Napisałem abstrakcyjną klasę bazową, która implementuje OnClickListener, którą możesz zastąpić, która rozwiązuje ten problem, ignorując wszelkie kliknięcia w kolejce:

/** 
 * 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;
    }
}

Użycie jest takie samo jak OnClickListener, ale zamiast tego zastąp 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);
Rozpoznać
źródło
Dzięki za kod. Na podstawie tego, co tutaj napisałeś, stworzyłem podobną klasę, która zapobiega kliknięciom, jeśli przycisk lub jego rodzic jest ukryty - to zabawne, że Android będzie kolejkował kliknięcia, nawet jeśli ukryjesz przycisk natychmiast po kliknięciu.
nikib3ro
1
Mam podobne rozwiązanie - możesz po prostu użyć tej klasy w xml i zawinie ona dla Ciebie ClickListeners github.com/doridori/AndroidUtilDump/blob/master/android/src/ ...
Dori
2
To dobre rozwiązanie, ale onClick () i reset () muszą być zsynchronizowane, w przeciwnym razie podwójne kliknięcie może się wkraść.
Tom anMoney.
6
@TomanMoney, jak? Czy nie wszystkie zdarzenia związane z kliknięciami występują w jednym wątku interfejsu użytkownika?
Ken
@Dori link nie żyje
naXa
36

Możesz to zrobić w bardzo fantazyjny sposób za pomocą funkcji rozszerzenia Kotlin i RxBinding

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

lub

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()
        }
    })
}

a potem tylko:

View.clickWithDebounce{ Your code }
Yvgen
źródło
over engenering
Serg Burlaka
3
Odbicie dla Rx nie zadziała tutaj dobrze. Zamiast tego „ThrottleFirst” powinien pasować lepiej. demo.nimius.net/debounce_throttle tutaj jest przykład, jak się różnią. PS: a właściwie twoja implementacja clickWithDebounce to implementacja przepustnicy, a nie
debounce
13

Ja też mam podobny problem, wyświetlałem jakiś datepicker i timepickers, gdzie czasami klikałem 2 razy. Rozwiązałem to przez to

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);
}

Możesz zmienić czas w zależności od wymagań. Ta metoda działa dla mnie.

Mudassar
źródło
To jest prawdziwe rozwiązanie, ponieważ ponownie aktywuje przycisk po upływie określonego czasu. Inne rozwiązania blokują przycisk na stałe, jeśli klikniesz szybko dwa razy. To rozwiązanie rozwiązuje problem! Dzięki
Néstor
10

setEnabled(false) u mnie działa idealnie.

Chodzi o to, że piszę { setEnabled(true); }na początku i robię to falseza pierwszym kliknięciem przycisku.

saurabh
źródło
9

Wiem, że to stare pytanie, ale dzielę się najlepszym rozwiązaniem, jakie znalazłem, aby rozwiązać ten powszechny problem

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

I w innym pliku, takim jak 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);
}
gustavo
źródło
8

Rzeczywistym rozwiązaniem tego problemu jest użycie setEnabled (false), które wyszarzają przycisk i setClickable (false), co sprawia, że ​​nie można odebrać drugiego kliknięcia. Przetestowałem to i wydaje się być bardzo skuteczne.

EpicOfChaos
źródło
7

Jeśli ktoś nadal szuka krótkiej odpowiedzi, możesz skorzystać z poniższego kodu

 private static long mLastClickTime = 0;
  if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) { // 1000 = 1second
         return;
    }
 mLastClickTime = SystemClock.elapsedRealtime();

Ten kod zostanie wprowadzony do środka za if statementkażdym razem, gdy użytkownik kliknie na przycisk, View within 1 seconda następnie return;zostanie zainicjowany i dalszy kod nie zostanie zainicjowany.

Rakshit Nawani
źródło
2
To powinna być akceptowana odpowiedź. Super proste i działa, nawet jeśli klikniesz bardzo szybko! Dzięki za to.
Geoffroy CALA
7

K leanest Kotlin idiomatyczne sposób:

class OnSingleClickListener(private val block: () -> Unit) : View.OnClickListener {

    private var lastClickTime = 0L

    override fun onClick(view: View) {
        if (SystemClock.elapsedRealtime() - lastClickTime < 1000) {
            return
        }
        lastClickTime = SystemClock.elapsedRealtime()

        block()
    }
}

fun View.setOnSingleClickListener(block: () -> Unit) {
    setOnClickListener(OnSingleClickListener(block))
}

Stosowanie:

button.setOnSingleClickListener { ... }
Powietrzny jeźdźca
źródło
6

Moje rozwiązanie to próba użycia booleanzmiennej:

public class Blocker {
    private static final int DEFAULT_BLOCK_TIME = 1000;
    private boolean mIsBlockClick;

    /**
     * Block any event occurs in 1000 millisecond to prevent spam action
     * @return false if not in block state, otherwise return true.
     */
    public boolean block(int blockInMillis) {
        if (!mIsBlockClick) {
            mIsBlockClick = true;
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mIsBlockClick = false;
                }
            }, blockInMillis);
            return false;
        }
        return true;
    }

    public boolean block() {
        return block(DEFAULT_BLOCK_TIME);
    }
}

I używając jak poniżej:

view.setOnClickListener(new View.OnClickListener() {
            private Blocker mBlocker = new Blocker();

            @Override
            public void onClick(View v) {
                if (!mBlocker.block(block-Time-In-Millis)) {
                    // do your action   
                }
            }
        });

AKTUALIZACJA : rozwiązanie Kotlin, używając rozszerzenia widoku

fun View.safeClick(listener: View.OnClickListener, blockInMillis: Long = 500) {
    var lastClickTime: Long = 0
    this.setOnClickListener {
        if (SystemClock.elapsedRealtime() - lastClickTime < blockInMillis) return@setOnClickListener
        lastClickTime = SystemClock.elapsedRealtime()
        listener.onClick(this)
    }
}
GianhTran
źródło
5

Click Guard działa dobrze z Butter Knife

ClickGuard.guard(mPlayButton);
thanhbinh84
źródło
4
oddzielne linrary dla uchwytu podwójne kliknięcie na przycisk? ha
Serg Burlaka
Czy mogę użyć tego przycisku niestandardowego?
Ara Badalyan
@AraBadalyan, co masz na myśli mówiąc „wewnątrz”. Po prostu podaj swój przycisk niestandardowy jako parametr metody ochrony. Wtedy twój przycisk będzie chroniony przed podwójnym kliknięciem
thanhbinh84
Chodzi mi o to, że nie chcę dodawać ClickGuard.guard (mPlayButton) do wszystkich działań, które używają onclick. Chcę utworzyć przycisk zakresu CustomButton i umieścić ClickGuard w CustomButton. Ale kiedy dodałem ClickGuard w konstruktorze CustomButton, nie zadziałało.
Ara Badalyan
@AraBadalyan to prawda. To nie działa w ten sposób.
thanhbinh84
5

w mojej sytuacji korzystałem z widoku przycisków i zbyt szybko przejmował on kliknięcia. po prostu wyłącz klikalne i włącz je ponownie po kilku sekundach ...

Zasadniczo stworzyłem klasę opakowującą, która otacza Twoje widoki onClickListener. Jeśli chcesz, możesz również ustawić niestandardowe opóźnienie.

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);
        }
    }

a żeby to nazwać, po prostu zrób to:

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

lub podaj własne opóźnienie:

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

AKTUALIZACJA: Powyżej trochę staromodny teraz, gdy RxJava jest tak powszechna. jak wspominali inni, w Androidzie możemy użyć przepustnicy, aby spowolnić kliknięcia. oto jeden przykład:

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

możesz użyć do tego tej biblioteki: implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'

j2emanue
źródło
4
    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            //to prevent double click
            button.setOnClickListener(null);
        }
    });
Indrek Kõue
źródło
4

Możesz użyć tej metody. Korzystając z post delay, możesz zająć się zdarzeniami podwójnego kliknięcia.

void debounceEffectForClick (widok widoku) {

    view.setClickable(false);

    view.postDelayed(new Runnable() {
        @Override
        public void run() {
            view.setClickable(true);

        }
    }, 500);
}
manmohan
źródło
4

Rozszerzenie Kotlin, które pozwala na zwięzły kod wbudowany i zmienne czasy oczekiwania na podwójne kliknięcie

fun View.setDoubleClickListener(listener: View.OnClickListener, waitMillis : Long = 1000) {
    var lastClickTime = 0L
    setOnClickListener { view ->
        if (System.currentTimeMillis() > lastClickTime + waitMillis) {
            listener.onClick(view)
            lastClickTime = System.currentTimeMillis()
        }
    }
}

Stosowanie:

anyView.setNoDoubleClickListener(View.OnClickListener { v ->
    // do stuff
})

Lub

anyView.setNoDoubleClickListener(View.OnClickListener { v ->
    // do stuff
}, 1500)
Jim
źródło
Świetnie, każdy powinien tego używać, jest to absolutnie fajny fragment kodu i świetny powód, dla którego wszyscy powinni przejść na kotlin.
Achmad Naufal Syafiq,
Byłoby ładniej, gdyby parametr waitMillis został po prostu zakodowany na stałe, wtedy można usunąć nawiasy zewnętrzne.
WindRider
4

Poniższy kod uniemożliwi użytkownikowi wielokrotne kliknięcie w ułamku sekundy i zezwoli dopiero po 3 sekundach.

private long lastClickTime = 0;

View.OnClickListener buttonHandler = new View.OnClickListener() {
    public void onClick(View v) {
        // preventing double, using threshold of 3000 ms
        if (SystemClock.elapsedRealtime() - lastClickTime < 3000){
            return;
        }

        lastClickTime = SystemClock.elapsedRealtime();
    }
}
Milan Sheth
źródło
3

Wygląda na to, że ustawienie słuchaczy kliknięć w onResume i wyłączenie ich w onPause też działa.

khendricks
źródło
3

U mnie pomogło tylko zapamiętanie znacznika czasu i sprawdzenie go (że od poprzedniego kliknięcia minęło więcej niż 1 sekunda).

shtolik
źródło
3

Mam nadzieję, że to Ci pomoże, umieść kod w programie obsługi zdarzeń.

// ------------------------------------------------ --------------------------------

    boolean hasTag = null != which.getTag( R.id.preventing_double_click_tag );

    if ( hasTag ) {
        // Do not handle again...
        return;
    } else {
        which.setTag( R.id.action, Boolean.TRUE );

        which.postDelayed( new Runnable() {
            @Override
            public void run() {
                which.setTag( R.id.action, null );
                Log.d( "onActin", " The preventing double click tag was removed." );
            }

        }, 2000 );
    }
ONG
źródło
3

Nie znalazłem żadnej z tych sugestii, jeśli metoda onClick nie powraca natychmiast. Zdarzenie touch jest umieszczane w kolejce przez Androida, a następne onClick jest wywoływane dopiero po zakończeniu pierwszego. (Ponieważ jest to wykonywane w jednym wątku interfejsu użytkownika, jest to naprawdę normalne.) Musiałem użyć czasu, w którym funkcja onClick jest zakończona + jedną zmienną logiczną, aby zaznaczyć, czy dany onClick działa. Oba te atrybuty znacznika są statyczne, aby uniknąć jednoczesnego działania onClickListener. (Jeśli użytkownik kliknie inny przycisk) Możesz po prostu zamienić swój OnClickListener na tę klasę i zamiast implementować metodę onClick, musisz zaimplementować abstrakcyjną metodę oneClick ().

    abstract public class OneClickListener implements OnClickListener {

    private static boolean started = false;
    private static long lastClickEndTime = 0;

    /* (non-Javadoc)
     * @see android.view.View.OnClickListener#onClick(android.view.View)
     */
    @Override
    final public void onClick(final View v) {
        if(started || SystemClock.elapsedRealtime()-lastClickEndTime <1000 ){
            Log.d(OneClickListener.class.toString(), "Rejected double click, " + new Date().toString() );
            return; 
        }
        Log.d(OneClickListener.class.toString(), "One click, start: " + new Date().toString() );
        try{
            started = true;
            oneClick(v);
        }finally{
            started = false;
            lastClickEndTime = SystemClock.elapsedRealtime();
            Log.d(OneClickListener.class.toString(), "One click, end: " + new Date().toString() );
        }
    }

    abstract protected void oneClick(View v);
}
linczy
źródło
3

możesz również użyć powiązań rx autorstwa Jake Wharton, aby to osiągnąć. oto próbka, która dzieli 2 sekundy między kolejnymi kliknięciami:

RxView.clicks(btnSave)
                .throttleFirst(2000, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Object>() {
                    @Override
                    public void accept( Object v) throws Exception {
//handle onclick event here
                });

// uwaga: zignoruj ​​Object v w tym przypadku i myślę, że zawsze.

j2emanue
źródło
3

Kotlin tworzy klasę SafeClickListener

class SafeClickListener(
        private var defaultInterval: Int = 1000,
        private val onSafeCLick: (View) -> Unit
) : View.OnClickListener {
    private var lastTimeClicked: Long = 0    override fun onClick(v: View) {
        if (SystemClock.elapsedRealtime() - lastTimeClicked < defaultInterval) {
            return
        }
        lastTimeClicked = SystemClock.elapsedRealtime()
        onSafeCLick(v)
    }
}

utwórz funkcję w baseClass lub w innym przypadku

fun View.setSafeOnClickListener(onSafeClick: (View) -> Unit) {val safeClickListener = SafeClickListener {
        onSafeClick(it)
    }
    setOnClickListener(safeClickListener)
}

i użyj po kliknięciu przycisku

btnSubmit.setSafeOnClickListener {
    showSettingsScreen()
}
jai khambhayta
źródło
1
Najczystsze rozwiązanie z rozszerzeniami! Dzięki!
android_dev
3

W Kotlin

button.setOnClickListener { 
    it?.apply { isEnabled = false; postDelayed({ isEnabled = true }, 400) } //400 ms
    //do your work
}
Владислав Прасков
źródło
2

Ustawienie opcji Klikalny na fałsz nie działa przy pierwszym dwukrotnym kliknięciu, ale kolejne podwójne kliknięcia są blokowane. To tak, jakby delegat kliknięcia ładowania za pierwszym razem był wolniejszy, a drugie kliknięcie było przechwytywane przed zakończeniem pierwszego.

        Button button = contentView.FindViewById<Button>(Resource.Id.buttonIssue);
        button.Clickable = false;
        IssueSelectedItems();
        button.Clickable = true;
KawBoy
źródło
2

Naprawiam ten problem za pomocą dwóch klas, jednej podobnej do odpowiedzi @ jinshiyi11, a druga opiera się na jawnym kliknięciu, w tym przypadku możesz kliknąć przycisk tylko raz, jeśli chcesz kolejne kliknięcie, musisz to wyraźnie wskazać .

/**
 * Listener que sólo permite hacer click una vez, para poder hacer click
 * posteriormente se necesita indicar explicitamente.
 *
 * @author iberck
 */
public abstract class OnExplicitClickListener implements View.OnClickListener {

    // you can perform a click only once time
    private boolean canClick = true;

    @Override
    public synchronized void onClick(View v) {
        if (canClick) {
            canClick = false;
            onOneClick(v);
        }
    }

    public abstract void onOneClick(View v);

    public synchronized void enableClick() {
        canClick = true;
    }

    public synchronized void disableClick() {
        canClick = false;
    }
}

Przykład użycia:

OnExplicitClickListener clickListener = new OnExplicitClickListener() {
    public void onOneClick(View v) {
        Log.d("example", "explicit click");
        ...
        clickListener.enableClick();    
    }
}
button.setOnClickListener(clickListener);
iberck
źródło
2
final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {

    private final AtomicBoolean onClickEnabled = new AtomicBoolean(true);

    @Override
    public void onClick(View v) {
        Log.i("TAG", "onClick begin");
        if (!onClickEnabled.compareAndSet(true, false)) {
            Log.i("TAG", "onClick not enabled");
            return;
        }

        button.setEnabled(false);

        // your action here

        button.setEnabled(true);
        onClickEnabled.set(true);
        Log.i("TAG", "onClick end");
    }
});
Milan Hlinák
źródło
View Listeners są zawsze wywoływani w jednym wątku (głównym), więc użycie AtomicBooleannie może naprawdę pomóc.
WindRider,
2

Spróbuj tego, to działa:

mButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {

                mSlotLayout.setEnabled(false);

        //      do your work here

                Timer buttonTimer = new Timer();
                buttonTimer.schedule(new TimerTask() {

                    @Override
                    public void run() {

                        runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                mButton.setEnabled(true);
                            }
                        });
                    }
                }, 500); // delay button enable for 0.5 sec
    }
});
Król Mszy
źródło