Android verhindert Doppelklick auf eine Schaltfläche

176

Was ist der beste Weg, um Doppelklicks auf eine Schaltfläche in Android zu verhindern?

Androider
quelle
3
Siehe qezts Lösung, nur sie ist voll funktionsfähig
Gennadiy Ryabkin
3
Die Lösung von qezt sollte akzeptiert worden sein, damit die Besucher dieser Seite den Nachteil der Verwendung von setEnabled (false) kennen.
LoveForDroid
Sie können meine Bibliothek mit der Lösung für den letzten Klick testen
Rex Lam
1
@ Androider bitte ändern Sie Ihre beste Antwort
Amir133

Antworten:

86

Deaktivieren Sie die Schaltfläche mit, setEnabled(false)bis der Benutzer sicher darauf klicken kann.

CommonsWare
quelle
47
setEnabled (false) scheint nicht "schnell" genug zu funktionieren. Ich habe einen View.OnClickListener.onClick (Ansicht) für eine Schaltfläche eingerichtet. Das erste, was ich in onClick () mache, ist eine Protokollanweisung zu schreiben, die zweite Anweisung ist button.setEnabled (false). Wenn ich schnell in den Emulator doppelklicke, wird die Protokollanweisung zweimal angezeigt! Selbst wenn direkt danach ein setClickable (false) hinzugefügt wird, wird die log-Anweisung zweimal angezeigt.
QQQuestions
Hmmm, vielleicht wird der Code bis zum setEnabled (true) am Ende von onClick () so schnell ausgeführt, dass er bereits wieder aktiviert ist ...
QQQuestions
91
Ich hatte ein ähnliches Problem. Laut einem hilfreichen Gentleman stellt Android die Klicks tatsächlich in die Warteschlange, sodass es keine Rolle spielt, wie schnell oder langsam Ihr onClick () - Code ausgeführt wird. nur wie schnell Sie auf die Schaltfläche klicken. Dh. Möglicherweise haben Sie die Schaltfläche bereits deaktiviert, aber die Klickwarteschlange wurde bereits mit zwei oder drei Klicks gefüllt. Das Deaktivieren der Schaltfläche hat keine Auswirkungen auf die Zustellung von Klicks in der Warteschlange. (obwohl es vielleicht sollte?)
Nick
3
Dieser seltene Moment, in dem Sie "jemanden" sehen, gibt eine genaue Antwort und keine abstrakten Antworten auf die gestellte Frage ..: P
Rahul
Dies ist nicht immer die richtige Lösung. Wenn Ihr onClick-Vorgang teuer ist, wird die Schaltfläche nicht schnell genug deaktiviert. Die vollständige Lösung IMHO besteht darin, die letzte Klickzeit zu verwenden, aber auch die Schaltfläche zu deaktivieren, um zu vermeiden, dass der Benutzer erneut darauf tippt, wenn Sie erwarten, dass der Vorgang eine Weile dauert (z. B. Anmelden).
Sarang
364

Das Speichern einer letzten Klickzeit beim Klicken verhindert dieses Problem.

dh

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
quelle
21
Dies ist die einzige Lösung, die einen Doppelklick tatsächlich verhindert. Ich habe gerade eine Stunde damit verbracht, alle anderen zu testen, da diese Methode ziemlich umständlich ist, aber keine von ihnen konnte ein schnelles doppeltes Tippen auf eine Ansicht außer dieser verhindern. Google bitte beheben Sie dieses :)
ashishduh
6
Diese Lösung funktioniert einwandfrei. Diese Lösung funktioniert auch, wenn Sie mehrere Schaltflächen auf dem Bildschirm haben und jeweils nur auf eine Schaltfläche klicken möchten.
nichtig
12
Dies verhindert Doppelklicks nicht vollständig, wenn Sie schnell genug doppelklicken.
Loc
4
Beste Antwort, es sollte oben sein
Gennadiy Ryabkin
3
Diese Lösung sollte die richtige Antwort sein ... setEnabled (false) reicht nicht aus.
Heloisasim
54

Meine Lösung ist

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

}

Die Verwendung ähnelt der von OnClickListener, überschreibt jedoch stattdessen onSingleClick ():

mTextView.setOnClickListener(new OnSingleClickListener() {
            @Override
            public void onSingleClick(View v) {
                if (DEBUG)
                    Log.i("TAG", "onclick!");
            }
     };
jinshiyi11
quelle
1
Einfach und perfekt, um Doppelberührungen automatisch zu verhindern.
Benjamin Piette
1
Dies verhindert Doppelklicks nicht vollständig, wenn Sie schnell genug doppelklicken.
Loc
1
Tolle Lösung. Ich habe gerade MIN_CLICK_INTERVAL = 1000 geändert.
Nizam
5
Wenn ich alle 0,5 Sekunden genau auf die Schaltfläche klicken würde, würde keiner meiner nachfolgenden Klicks durchkommen, da mLastClickTime bei jedem Klick aktualisiert würde. Mein Vorschlag wäre, mLastClickTime zuzuweisen, nachdem Sie das Intervall überprüft haben.
k2col
mLastClickTime = currentClickTime; sollte nach if (elapsedTime <= MIN_CLICK_INTERVAL) return platziert werden;
Loyea
41

Das Deaktivieren der Schaltfläche oder das Deaktivieren der Option "Nicht anklickbar" reicht nicht aus, wenn Sie in onClick () rechenintensiv arbeiten, da Klickereignisse in die Warteschlange gestellt werden können, bevor die Schaltfläche deaktiviert werden kann. Ich habe eine abstrakte Basisklasse geschrieben, die OnClickListener implementiert, die Sie stattdessen überschreiben können. Sie behebt dieses Problem, indem Sie alle in der Warteschlange befindlichen Klicks ignorieren:

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

Die Verwendung ist mit OnClickListener identisch, überschreibt jedoch stattdessen 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);
Ken
quelle
Danke für den Code. Basierend auf dem, was Sie hier geschrieben haben, habe ich eine ähnliche Klasse erstellt, die Klicks verhindert, wenn die Schaltfläche oder deren übergeordnetes Element ausgeblendet ist. Es ist lustig, dass Android Klicks in die Warteschlange stellt, selbst wenn Sie die Schaltfläche unmittelbar nach dem Klicken ausblenden.
Nikib3ro
1
Ich habe eine ähnliche Lösung - man muss nur diese Klasse in XML verwenden kann , und es wird die clickListeners Sie einpacken github.com/doridori/AndroidUtilDump/blob/master/android/src/...
Dori
2
Dies ist eine gute Lösung, aber onClick () und reset () müssen synchronisiert werden, sonst kann sich noch ein Doppelklick einschleichen.
Tom anMoney
6
@TomanMoney, wie? Treten nicht alle Klickereignisse in einem einzigen UI-Thread auf?
Ken
@ Dori der Link ist tot
naXa
36

Mit Kotlin Extension Functions und RxBinding können Sie dies auf sehr ausgefallene Weise tun

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

oder

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

und dann einfach:

View.clickWithDebounce{ Your code }
Yvgen
quelle
über das Erzeugen
Serg Burlaka
3
Debounce für Rx wird hier nicht gut funktionieren. Stattdessen sollte "ThrottleFirst" besser passen. demo.nimius.net/debounce_throttle hier ist ein Beispiel dafür, wie sie sich unterscheiden. PS: und tatsächlich ist Ihre clickWithDebounce-Implementierung eine Gaspedalimplementierung, keine Entprellung
krossovochkin
13

Ich habe auch ein ähnliches Problem. Ich habe einige Datums- und Zeitmesser angezeigt, bei denen es manchmal zweimal zu einem Klick kam. Ich habe es dadurch gelöst

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

Sie können die Zeit je nach Ihren Anforderungen ändern. Diese Methode funktioniert bei mir.

Mudassar
quelle
Dies ist die eigentliche Lösung, da die Schaltfläche nach Ablauf der Zeit automatisch wieder aktiviert wird. Die anderen Lösungen blockieren die Schaltfläche dauerhaft, wenn Sie zweimal schnell klicken. Diese Lösung behebt das Problem! Danke
Néstor
10

setEnabled(false) funktioniert perfekt für mich.

Die Idee ist, ich schreibe { setEnabled(true); }am Anfang und mache es einfach falsebeim ersten Klick auf die Schaltfläche.

Saurabh
quelle
9

Ich weiß, dass es eine alte Frage ist, aber ich teile die beste Lösung, die ich gefunden habe, um dieses häufige Problem zu lösen

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

Und in einer anderen Datei wie 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
quelle
8

Die eigentliche Lösung für dieses Problem besteht darin, setEnabled (false) zu verwenden, mit dem die Schaltfläche ausgegraut wird, und setClickable (false), mit dem der zweite Klick nicht empfangen werden kann. Ich habe dies getestet und es scheint sehr effektiv zu sein.

EpicOfChaos
quelle
7

Wenn jemand noch nach einer kurzen Antwort sucht, können Sie den folgenden Code verwenden

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

Dieser Code wird in das if statementVerzeichnis eingefügt, wenn der Benutzer auf das klickt, View within 1 secondund dann return;wird der Code initiiert und der weitere Code wird nicht initiiert.

Rakshit Nawani
quelle
2
Dies sollte die akzeptierte Antwort sein. Super einfach und es funktioniert auch wenn Sie sehr schnell klicken! Danke dafür.
Geoffroy CALA
7

Der K LEANEST Kotlin idiomatische Weg:

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

Verwendung:

button.setOnSingleClickListener { ... }
Windreiter
quelle
6

Meine Lösung besteht darin, eine booleanVariable zu verwenden:

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

Und wie folgt verwenden:

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

UPDATE : Kotlin-Lösung mit Ansichtserweiterung

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
quelle
5

Click Guard funktioniert gut mit Butter Knife

ClickGuard.guard(mPlayButton);
thanhbinh84
quelle
4
Separate Linrary für Handle Doppelklick auf Button? ha
Serg Burlaka
Kann ich diese benutzerdefinierte Schaltfläche verwenden?
Ara Badalyan
@AraBadalyan was meinst du mit 'innen'. Übergeben Sie einfach Ihre benutzerdefinierte Schaltfläche als Parameter für die Schutzmethode. Dann wird Ihre Schaltfläche vor Doppelklick
geschützt
Ich möchte ClickGuard.guard (mPlayButton) nicht in allen Aktivitäten hinzufügen, die onclick verwenden. Ich möchte CustomButton Extent Button erstellen und ClickGuard in CustomButton einfügen. Aber als ich ClickGuard im CustomButton-Konstruktor hinzufügte, funktionierte es nicht.
Ara Badalyan
@AraBadalyan das stimmt. So funktioniert das nicht.
thanhbinh84
5

In meiner Situation habe ich eine Schaltflächenansicht verwendet und die Klicks wurden zu schnell ausgeführt. Deaktivieren Sie einfach das anklickbare und aktivieren Sie es nach einigen Sekunden wieder ...

Grundsätzlich habe ich eine Wrapper-Klasse erstellt, die Ihre Views onClickListener umschließt. Sie können auch eine benutzerdefinierte Verzögerung festlegen, wenn Sie möchten.

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

und um es zu nennen, machen Sie einfach Folgendes:

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

oder geben Sie Ihre eigene Verzögerung an:

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

UPDATE: Oben ein bisschen altmodisch, jetzt wo RxJava so weit verbreitet ist. Wie andere bereits erwähnt haben, könnten wir in Android einen Gashebel verwenden, um die Klicks zu verlangsamen. Hier ist ein Beispiel:

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

Sie können diese Bibliothek dafür verwenden: implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'

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

Sie können diese Methode verwenden. Durch die Verwendung der Nachverzögerung können Sie auf Doppelklickereignisse achten.

void debounceEffectForClick (Ansichtsansicht) {

    view.setClickable(false);

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

        }
    }, 500);
}
Manmohan
quelle
4

Kotlin-Erweiterung, die präzise Inline-Code- und variable Doppelklick-Wartezeiten ermöglicht

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

Verwendung:

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

Oder

anyView.setNoDoubleClickListener(View.OnClickListener { v ->
    // do stuff
}, 1500)
Jim
quelle
Genial, jeder sollte dies verwenden, es ist ein absolut netter Code und ein guter Grund, warum jeder nach Kotlin migrieren sollte.
Achmad Naufal Syafiq
Könnte schöner sein, wenn die waitMillis nur fest codiert ist, dann können die äußeren Klammern entfernt werden.
WindRider
4

Der folgende Code verhindert, dass der Benutzer innerhalb von Sekundenbruchteilen mehrmals klickt, und lässt ihn erst nach 3 Sekunden zu.

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
quelle
3

Es scheint, dass das Setzen Ihrer Klick-Listener in onResume und das Nullstellen in onPause ebenfalls den Trick macht.

Khendricks
quelle
3

Für mich hat es nur geholfen, mich an den Zeitstempel zu erinnern und ihn zu überprüfen (der seit dem letzten Klick mehr als 1 Sekunde vergangen ist).

shtolik
quelle
3

Ich hoffe, dies kann Ihnen helfen, den Code in Ihren Event-Handler zu setzen.

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

    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
quelle
3

Ich habe festgestellt, dass keiner dieser Vorschläge funktioniert, wenn die onClick-Methode nicht sofort zurückgegeben wird. Das Touch-Ereignis wird von Android in die Warteschlange gestellt und der nächste onClick wird erst aufgerufen, nachdem der erste abgeschlossen ist. (Da dies auf einem UI-Thread durchgeführt wird, ist dies wirklich normal.) Ich musste die Zeit verwenden, zu der die onClick-Funktion beendet ist + eine boolesche Variable, um zu markieren, ob der angegebene onClick ausgeführt wird. Diese beiden Markerattribute sind statisch, um zu vermeiden, dass onClickListener gleichzeitig ausgeführt wird. (Wenn der Benutzer auf eine andere Schaltfläche klickt) Sie können Ihren OnClickListener einfach durch diese Klasse ersetzen. Anstatt die onClick-Methode zu implementieren, müssen Sie die abstrakte oneClick () -Methode implementieren.

    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
quelle
3

Sie können auch RX-Bindungen von Jake Wharton verwenden , um dies zu erreichen. Hier ist ein Beispiel, das 2 Sekunden zwischen aufeinanderfolgenden Klicks auffüllt:

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

// Anmerkung: ignoriere das Objekt v in diesem Fall und ich denke immer.

j2emanue
quelle
3

Kotlin erstellt die Klasse 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)
    }
}

Erstellen Sie eine Funktion in baseClass oder sonst

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

und auf Knopfdruck verwenden

btnSubmit.setSafeOnClickListener {
    showSettingsScreen()
}
Jai Khambhayta
quelle
1
Die sauberste Lösung mit Erweiterungen! Vielen Dank!
android_dev
3

In Kotlin

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

Das Setzen von Clickable auf false funktioniert nicht beim ersten Doppelklick, aber nachfolgende Doppelklicks werden blockiert. Es ist, als ob der Ladeklick-Delegat beim ersten Mal langsamer ist und der zweite Klick erfasst wird, bevor der erste abgeschlossen ist.

        Button button = contentView.FindViewById<Button>(Resource.Id.buttonIssue);
        button.Clickable = false;
        IssueSelectedItems();
        button.Clickable = true;
KawBoy
quelle
2

Ich behebe dieses Problem mit zwei Klassen, eine ähnlich der Antwort von @ jinshiyi11, und der Anoter basiert auf einem expliziten Klick. In diesem Fall können Sie nur einmal auf eine Schaltfläche klicken. Wenn Sie einen weiteren Klick wünschen, müssen Sie ihn explizit angeben .

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

Anwendungsbeispiel:

OnExplicitClickListener clickListener = new OnExplicitClickListener() {
    public void onOneClick(View v) {
        Log.d("example", "explicit click");
        ...
        clickListener.enableClick();    
    }
}
button.setOnClickListener(clickListener);
iberck
quelle
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
quelle
View-Listener werden immer in einem einzelnen Thread (main) aufgerufen, sodass die Verwendung AtomicBooleannicht wirklich helfen kann.
WindRider
2

Versuchen Sie dies, es funktioniert:

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
    }
});
König der Massen
quelle