Android ป้องกันการดับเบิลคลิกที่ปุ่ม


177

วิธีที่ดีที่สุดในการป้องกันการคลิกสองครั้งบนปุ่มใน Android คืออะไร?


3
ดูโซลูชันของ qezt เท่านั้นที่สามารถใช้งานได้อย่างสมบูรณ์
Gennadiy Ryabkin

3
โซลูชันของ qezt ควรได้รับการยอมรับเพื่อให้ผู้ที่เข้าชมหน้านี้ทราบถึงข้อเสียเปรียบในการใช้ setEnabled (false)
LoveForDroid

คุณสามารถลองใช้ห้องสมุดของฉันโดยใช้วิธีแก้ปัญหาการคลิกครั้งสุดท้าย: github.com/RexLKW/SClick
Rex Lam

1
@Androider โปรดเปลี่ยนคำตอบที่ดีที่สุดของคุณ
Amir133

คำตอบ:


87

ปิดใช้งานปุ่มด้วยsetEnabled(false)จนกว่าจะปลอดภัยสำหรับผู้ใช้คลิกอีกครั้ง


47
setEnabled (false) ดูเหมือนว่าจะไม่ "เร็ว" เพียงพอ ฉันได้ตั้งค่า ViewOnClickListener.onClick (ดู) สำหรับปุ่มแล้ว สิ่งแรกที่ฉันทำใน onClick () คือการเขียนคำสั่งบันทึกคำสั่งที่ 2 คือ button.setEnabled (false) เมื่อคลิกสองครั้งอย่างรวดเร็วในอีมูเลเตอร์ฉันเห็นข้อความบันทึกปรากฏขึ้นสองครั้ง! แม้ว่าจะเพิ่ม setClickable (false) หลังจากนั้นคำสั่งบันทึกจะปรากฏขึ้นสองครั้ง
QQQuestions

อืมรหัสอาจถึง setEnabled (จริง) ที่ส่วนท้ายของ onClick () กำลังดำเนินการอย่างรวดเร็วจนเปิดใช้งานอีกครั้ง ...
QQQuestions

91
ฉันมีปัญหาที่คล้ายกัน ตามสุภาพบุรุษผู้ช่วยเหลือคนหนึ่ง Android จะรอคิวการคลิกดังนั้นจึงไม่สำคัญว่าโค้ด onClick () ของคุณจะทำงานเร็วหรือช้าเพียงใด เพียงแค่คุณคลิกปุ่มเร็วเท่าไหร่ กล่าวคือ คุณอาจปิดใช้งานปุ่มแล้ว แต่คิวการคลิกนั้นเต็มไปด้วยการคลิกสองหรือสามครั้งและการปิดใช้งานปุ่มนั้นไม่มีผลต่อการส่งการคลิกที่อยู่ในคิว (แม้ว่ามันอาจจะควร?)
นิค

3
ช่วงเวลาที่หายากนั้นเมื่อคุณเห็น 'บางคน' ให้คำตอบที่แน่นอนและไม่ใช่ abstraaaaaaaact คำตอบสำหรับคำถามที่ถูกถาม .. : P
Rahul

นี่ไม่ใช่ทางออกที่ถูกต้องเสมอไป หากการดำเนินการ onClick ของคุณมีราคาแพงปุ่มจะไม่ปิดการทำงานอย่างรวดเร็ว โซลูชันเต็มรูปแบบ IMHO คือการใช้เวลาคลิกครั้งสุดท้าย แต่ยังปิดการใช้งานปุ่มเพื่อหลีกเลี่ยงผู้ใช้แตะที่มันอีกครั้งหากคุณคาดว่าการดำเนินการจะอยู่ได้นาน (เช่นการเข้าสู่ระบบ)
ซารัง

368

ประหยัดเวลาคลิกสุดท้ายเมื่อคลิกจะป้องกันปัญหานี้

กล่าวคือ

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

21
นี่เป็นทางออกเดียวที่ป้องกันการคลิกสองครั้งจริง ๆ ฉันใช้เวลาหนึ่งชั่วโมงในการลองวิธีอื่น ๆ ทั้งหมดเนื่องจากวิธีนี้ค่อนข้างหนา แต่ไม่มีใครสามารถป้องกันการแตะสองครั้งอย่างรวดเร็วของมุมมองยกเว้นอันนี้ Google โปรดแก้ไขสิ่งนี้ :)
ashishduh

6
โซลูชันนี้ใช้งานได้ดีโซลูชันนี้ยังใช้งานได้เมื่อคุณมีหลายปุ่มบนหน้าจอและคุณต้องการคลิกเพียงปุ่มเดียวในเวลา
ถือเป็นโมฆะ

12
สิ่งนี้ไม่ได้ป้องกันการคลิกสองครั้งอย่างสมบูรณ์หากคุณดับเบิลคลิกเร็วพอ
Loc

4
คำตอบที่ดีที่สุดควรอยู่ด้านบน
Gennadiy Ryabkin

3
วิธีแก้ปัญหานี้ควรเป็นคำตอบที่ถูกต้อง ... setEnabled (false) ไม่เพียงพอ
heloisasim

55

ทางออกของฉันคือ

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

1
ง่ายและสมบูรณ์แบบในการป้องกันการแตะสองครั้งโดยอัตโนมัติ
Benjamin Piette

1
สิ่งนี้ไม่ได้ป้องกันการคลิกสองครั้งอย่างสมบูรณ์หากคุณดับเบิลคลิกเร็วพอ
Loc

1
ทางออกที่ดี ฉันเพิ่งเปลี่ยน MIN_CLICK_INTERVAL = 1,000;
Nizam

5
ถ้าฉันต้องกดปุ่มให้ถูกต้องทุก 0.5 วินาทีการคลิกครั้งต่อไปของฉันจะไม่ผ่านเพราะ mLastClickTime จะได้รับการอัปเดตแต่ละครั้ง คำแนะนำของฉันคือการกำหนด mLastClickTime หลังจากที่คุณตรวจสอบช่วงเวลา
k2col

mLastClickTime = currentClickTime; ควรวางหลังจากถ้า (elapsedTime <= MIN_CLICK_INTERVAL) กลับมา;
Loyea

41

การปิดใช้งานปุ่มหรือการตั้งค่าที่ไม่สามารถคลิกได้นั้นไม่เพียงพอหากคุณกำลังทำงานอย่างหนักใน 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);

ขอบคุณสำหรับรหัส จากสิ่งที่คุณเขียนที่นี่ฉันได้สร้างคลาสที่คล้ายกันซึ่งป้องกันการคลิกถ้าปุ่มหรือเป็นพาเรนต์ถูกซ่อน - เป็นเรื่องตลกที่ Android จะจัดคิวการคลิกแม้ว่าคุณจะซ่อนปุ่มทันทีหลังจากคลิก
nikib3ro

1
ฉันมีวิธีแก้ปัญหาที่คล้ายกัน - คุณสามารถใช้คลาสนี้ใน xml และมันจะตัด clickListeners ให้คุณgithub.com/doridori/AndroidUtilDump/blob/master/android/src/…
Dori

2
นี่เป็นวิธีแก้ปัญหาที่ดี แต่ต้องมีการซิงโครไนซ์ onClick () และรีเซ็ต () มิฉะนั้นการดับเบิลคลิกยังสามารถแอบเข้าไปได้
Tom anMoney

6
@TomanMoney อย่างไร กิจกรรมการคลิกทั้งหมดไม่เกิดขึ้นในเธรด UI เดียวใช่ไหม
Ken

@Dori การเชื่อมโยงตาย
naXa

36

คุณสามารถทำได้ด้วยวิธีแฟนซีด้วยฟังก์ชั่น Kotlin Extensionและ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 }

มากกว่าการขุด
Serg Burlaka

3
Debounce สำหรับ Rx ใช้งานไม่ได้ที่นี่ แทน "ThrottleFirst" ควรพอดีดีกว่า demo.nimius.net/debounce_throttleนี่เป็นตัวอย่างเกี่ยวกับความแตกต่าง PS: และที่จริงแล้ว clickWith ของคุณกับการใช้งานลดลงคือการใช้เค้นไม่ได้ debounce
krossovochkin

13

ฉันยังพบปัญหาที่คล้ายกันฉันแสดง datepicker & timepickers ซึ่งบางครั้งก็มีการคลิก 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);
}

คุณสามารถเปลี่ยนเวลาขึ้นอยู่กับความต้องการของคุณ วิธีนี้ใช้ได้ผลสำหรับฉัน


นี่เป็นทางออกที่แท้จริงเนื่องจากจะเปิดใช้งานปุ่มอีกครั้งโดยอัตโนมัติหลังจากเวลาผ่านไป โซลูชันอื่น ๆ บล็อกปุ่มอย่างถาวรหากคุณคลิกสองครั้งอย่างรวดเร็ว วิธีนี้แก้ไขปัญหาได้! ขอบคุณ
Néstor

10

setEnabled(false) ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน

ความคิดคือฉันเขียน{ setEnabled(true); }ในการเริ่มต้นและเพียงแค่ทำให้มันfalseในคลิกแรกของปุ่ม


9

ฉันรู้ว่ามันเป็นคำถามเก่า แต่ฉันแบ่งปันทางออกที่ดีที่สุดที่ฉันพบเพื่อแก้ไขปัญหาที่พบบ่อยนี้

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

8

ทางออกที่แท้จริงของปัญหานี้คือการใช้ setEnabled (false) ซึ่งเป็นปุ่มสีเทาและ setClickable (false) ซึ่งทำให้ไม่สามารถรับการคลิกครั้งที่สองได้ฉันได้ทำการทดสอบแล้วและดูเหมือนว่าจะมีประสิทธิภาพมาก


7

หากใครบางคนยังคงมองหาคำตอบสั้น ๆ คุณสามารถใช้รหัสด้านล่าง

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

รหัสนี้จะเข้าไปข้างในif statementเมื่อใดก็ตามที่ผู้ใช้คลิกที่View within 1 secondและจากนั้นreturn;จะเริ่มต้นและรหัสเพิ่มเติมจะไม่เริ่มต้น


2
นี่ควรเป็นคำตอบที่ยอมรับได้ ง่ายสุด ๆ และใช้งานได้แม้ว่าคุณจะคลิกเร็วมาก! ขอบคุณสำหรับสิ่งนี้.
Geoffroy CALA

7

K leanest Kotlinวิธีสำนวน:

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

การใช้งาน:

button.setOnSingleClickListener { ... }

6

โซลูชันของฉันพยายามใช้booleanตัวแปร:

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

และใช้เป็นด้านล่าง:

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

อัปเดต : โซลูชัน Kotlin โดยใช้ส่วนขยายมุมมอง

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

5

Click Guardทำงานได้ดีกับ Butter Knife

ClickGuard.guard(mPlayButton);

4
separete linrary สำหรับจัดการดับเบิลคลิกที่ปุ่ม? ha
Serg Burlaka

ฉันสามารถใช้ปุ่มนี้ภายในปุ่มที่กำหนดเองได้หรือไม่?
Ara Badalyan

@AraBadalyan คุณหมายถึง 'ข้างใน' เพียงผ่านปุ่มที่กำหนดเองของคุณเป็นพารามิเตอร์สำหรับวิธีการป้องกัน จากนั้นปุ่มของคุณจะได้รับการปกป้องจากการดับเบิลคลิก
thanhbinh84

ฉันหมายความว่าฉันไม่ต้องการเพิ่ม ClickGuard.guard (mPlayButton) ในทุกกิจกรรมที่ใช้ onclick ฉันต้องการสร้างปุ่มขอบเขต CustomButton และวาง ClickGuard ไว้ใน CustomButton แต่เมื่อฉันเพิ่ม ClickGuard ในตัวสร้าง CustomButton มันไม่ทำงาน
Ara Badalyan

@AraBadalyan ถูกต้องแล้ว มันไม่ทำงานอย่างนั้น
thanhbinh84

5

ในสถานการณ์ของฉันฉันใช้มุมมองปุ่มและมันทำให้การคลิกเร็วเกินไป เพียงแค่ปิดการคลิกและเปิดใช้งานอีกครั้งหลังจากผ่านไปสองสามวินาที ...

โดยทั่วไปฉันทำคลาส wrapper ที่ล้อมรอบ Views ของคุณ 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

คุณสามารถใช้วิธีนี้ ด้วยการใช้การโพสต์ล่าช้าคุณสามารถดูแลกิจกรรมดับเบิลคลิกได้

เป็นโมฆะ debounceEffectForClick (ดูมุมมอง) {

    view.setClickable(false);

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

        }
    }, 500);
}

4

ส่วนขยาย Kotlin ที่ช่วยให้กระชับรหัสแบบอินไลน์ & ตัวแปรดับเบิลคลิกเวลารอ

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

การใช้งาน:

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

หรือ

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

ยอดเยี่ยมทุกคนควรใช้สิ่งนี้มันเป็นโค้ดที่ดีอย่างยิ่งและเหตุผลที่ดีว่าทำไมทุกคนควรโยกย้ายไปที่ kotlin
Achmad Naufal Syafiq

อาจดีกว่านี้ถ้า waitMillis เป็นฮาร์ดโค้ดเท่านั้นดังนั้นวงเล็บด้านนอกจะถูกกำจัด
WindRider

4

โค้ดด้านล่างจะป้องกันไม่ให้ผู้ใช้คลิกหลาย ๆ ครั้งภายในเสี้ยววินาทีและอนุญาตหลังจากผ่านไป 3 วินาทีเท่านั้น

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

3

ดูเหมือนว่าการตั้งค่าฟังเพลงคลิกของคุณใน onResume และลบล้างพวกเขาใน onPause ก็เป็นการหลอกลวงเช่นกัน


3

สำหรับฉันเท่านั้นที่จดจำการประทับเวลาและการตรวจสอบกับ (มากกว่า 1 วินาทีผ่านไปนับตั้งแต่การคลิกครั้งก่อน) ช่วย


3

ฉันหวังว่าสิ่งนี้จะช่วยคุณใส่รหัสในการจัดการเหตุการณ์ของคุณ

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

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

3

ฉันพบว่าคำแนะนำเหล่านี้ไม่สามารถใช้งานได้หากเมธอด onClick ไม่ส่งคืนทันที เหตุการณ์สัมผัสถูกจัดคิวโดย Android และ onClick ถัดไปจะถูกเรียกใช้หลังจากเหตุการณ์แรกเสร็จสิ้น (เนื่องจากสิ่งนี้ทำบนเธรด UI เดียวซึ่งเป็นเรื่องปกติจริงๆ) ฉันต้องการใช้เวลาที่ฟังก์ชัน onClick เสร็จ + ตัวแปรบูลีนหนึ่งตัวเพื่อทำเครื่องหมายว่า onClick ที่กำหนดกำลังทำงานอยู่หรือไม่ แอ็ตทริบิวต์ตัวทำเครื่องหมายทั้งสองเหล่านี้เป็นแบบสแตติกเพื่อหลีกเลี่ยง onClickListener ใด ๆ ให้รันในเวลาเดียวกัน (หากผู้ใช้คลิกที่ปุ่มอื่น) คุณสามารถแทนที่ OnClickListener ของคุณเป็นคลาสนี้ได้อย่างง่ายดายและแทนที่จะใช้เมธอด onClick คุณต้องใช้เมธอด 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);
}

3

คุณยังสามารถใช้การผูก rx โดย jake whartonเพื่อทำสิ่งนี้ให้สำเร็จ นี่คือตัวอย่างที่แผ่น 2 วินาทีระหว่างการคลิกต่อเนื่อง:

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

// หมายเหตุ: เพิกเฉยต่อ Object v ในกรณีนี้และฉันคิดเสมอ


3

Kotlin สร้างคลาส 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)
    }
}

สร้างฟังก์ชั่นใน baseClass หรืออื่น ๆ

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

และใช้เมื่อคลิกปุ่ม

btnSubmit.setSafeOnClickListener {
    showSettingsScreen()
}

1
ทางออกที่สะอาดที่สุดพร้อมส่วนขยาย! ขอบคุณ!
android_dev



2

การตั้งค่าแบบคลิกได้เป็นเท็จไม่ทำงานในการดับเบิลคลิกครั้งแรก แต่การคลิกสองครั้งต่อมาจะถูกบล็อก ดูเหมือนว่าการมอบหมายการโหลดการคลิกในครั้งแรกจะช้ากว่าและการคลิกครั้งที่สองจะถูกจับก่อนที่จะเสร็จสิ้นในครั้งแรก

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

2

ฉันจะแก้ไขปัญหานี้โดยใช้สอง clases หนึ่งคล้ายกับ @ jinshiyi11 คำตอบและ anoter จะขึ้นอยู่กับการคลิกที่ชัดเจนในเรื่องนี้คุณสามารถคลิกปุ่มเพียงครั้งเดียวเวลาถ้าคุณต้องการอีกคลิกคุณจะต้องแสดงให้เห็นว่ามันชัดเจน

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

ตัวอย่างการใช้งาน:

OnExplicitClickListener clickListener = new OnExplicitClickListener() {
    public void onOneClick(View v) {
        Log.d("example", "explicit click");
        ...
        clickListener.enableClick();    
    }
}
button.setOnClickListener(clickListener);

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

ผู้ฟังที่ดูจะถูกเรียกบนเธรดเดี่ยว (หลัก) เสมอดังนั้นการใช้AtomicBooleanไม่สามารถช่วยได้จริงๆ
WindRider

2

ลองสิ่งนี้มันใช้งานได้:

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
    }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.