Android防止双击按钮

时间:2011-04-09 23:49:54

标签: android android-button double-click

在Android中阻止双击按钮的最佳方法是什么?

52 个答案:

答案 0 :(得分:292)

点击时保存最后点击时间可以防止出现此问题。

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

答案 1 :(得分:68)

禁用setEnabled(false)按钮,直到用户再次点击它为止是安全的。

答案 2 :(得分: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);

答案 3 :(得分:39)

我的解决方案是

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

答案 4 :(得分:17)

您可以使用Kotlin Extension FunctionsRxBinding

以非常奇特的方式完成此操作
   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 }

答案 5 :(得分:11)

我也遇到了类似的问题,我正在显示一些日期选择器&amp;时间戳有时会点击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);
}

您可以根据需要更改时间。这种方法适合我。

答案 6 :(得分:8)

setEnabled(false)非常适合我。

我的想法是在开头编写{ setEnabled(true); },然后在第一次点击按钮时将其设为false

答案 7 :(得分:5)

这个问题的实际解决方案是使用灰色按钮的setEnabled(false)和setClickable(false)使得它无法接收到第二次点击我已经测试了它并且它似乎非常有效。

答案 8 :(得分:4)

在我的情况下,我使用的是按钮视图,而且点击过快。只需禁用可点击并在几秒钟后再次启用它...

基本上我创建了一个包装你的Views onClickListener的包装类。如果需要,您也可以设置自定义延迟。

yCoordBg1 += BACKGROUND_MOVE_SPEED * Gdx.graphics.getDeltaTime();
yCoordBg2 = yCoordbg1 + yMax;  // We move the background, not the camera
if (yCoordBg1 >= 0) {
    yCoordBg1 = yMax*(-1); yCoordBg2 = 0;
}
batch.begin();
batch.draw(background1, 0, yCoordBg1);
batch.draw(background2, 0, yCoordBg2);
batch.end();

并调用它只需执行此操作:

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

更新:现在RxJava如此普遍,现在已经过时了。正如其他人所提到的,在android中我们可以使用节流来减慢点击次数。这是一个例子:

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

您可以使用此库: RxView.clicks(myButton) .throttleFirst(2000, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) .subscribe { Log.d("i got delayed clicked") } }

答案 9 :(得分:3)

K 最简洁的科特林惯用方式:

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

答案 10 :(得分:3)

我的解决方案是尝试使用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   
                }
            }
        });

答案 11 :(得分:2)

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)

答案 12 :(得分:2)

如果有人仍在寻找简短的答案,您可以使用以下代码

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

只要用户点击if statement,此代码就会进入View within 1 second,然后return;将会启动,而其他代码将无法启动。

答案 13 :(得分:2)

我知道这是一个老问题,但我分享了我找到解决这个常见问题的最佳解决方案

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

在另一个文件中,例如Utils.java

    <p>
      <%= label_tag(:sk, "Skills:") %>
      <%= text_area_tag :sk, params[:sk], placeholder: "Enter skills", class: "form-control" %>
    </p> 

答案 14 :(得分:2)

Click Guard适用于Butter Knife

<div class="container-fluid">
        <div class="row">
            <div class="col-lg-3">
                <div id="categorymenu">
                    <center>  <h3>Categorieën</h3> </center>
                    <ul class="list-group">
                        <?php foreach (get_categories_h() as $category) : ?>
                            <li class="list-group-item">
                                <a href="#"><?php echo $category['name']; ?>
                                </a> 
                            </li>
                        <?php endforeach; ?>
                    </ul>
                </div>
            </div>
        </div>
    </div>

答案 15 :(得分:2)

似乎在onResume中设置你的点击监听器并在onPause中将它们归零也是有用的。

答案 16 :(得分:2)

我的解决方案(科特琳):

class OnDebouncedClickListener(private val delayInMilliSeconds: Long, val action: () -> Unit) : View.OnClickListener {
    var enable = true

    override fun onClick(view: View?) {
        if (enable) {
            enable = false
            view?.postDelayed(delayInMilliSeconds) { enable = true }
            action()
        }
    }
}

fun View.setOnDebouncedClickListener(delayInMilliSeconds: Long = 500, action: () -> Unit) {
    val onDebouncedClickListener = OnDebouncedClickListener(delayInMilliSeconds, action)
    setOnClickListener(onDebouncedClickListener)
}

使用:

button.apply {       
            setOnDebouncedClickListener {
                //your action on click
            }
        }

答案 17 :(得分:2)

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

答案 18 :(得分:2)

对我来说,只记住时间戳并检查它(自上次点击后超过1秒)帮助了。

答案 19 :(得分:2)

我希望这可以帮助你,把代码放在你的事件处理程序中。

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

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

答案 20 :(得分:2)

此解决方案(科特琳)对我有效:

abstract class SingleClickListener : View.OnClickListener {
    private val MIN_CLICK_INTERVAL: Long = 1000
    private var mLastClickTime: Long = 0

    abstract fun onSingleClick(v: View?)

    override fun onClick(v: View?) {
        if (mLastClickTime <= 0) {
            mLastClickTime = SystemClock.uptimeMillis()
            onSingleClick(v)
            return
        }

        if (SystemClock.uptimeMillis() - mLastClickTime <= MIN_CLICK_INTERVAL) {
            return
        }

        mLastClickTime = SystemClock.uptimeMillis()

        onSingleClick(v)
    }
}

用法:

someView.setOnClickListener(object : SingleClickListener() {
    override fun onSingleClick(v: View?) {
        v?.also { klik(it) }
    }
})

或创建扩展功能以轻松在视图上添加ClickListener:

fun View.click(klik: (View) -> Unit) {
    this.setOnClickListener(object : SingleClickListener() {
        override fun onSingleClick(v: View?) {
            v?.also { klik(it) }
        }
    })
}

// Usage
class XPerimentActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_xperiment_layout)

        submit_button.click {
           // do your magic
        }
    }
}

答案 21 :(得分:1)

Java中有一个本机的反跳点击侦听器

import numpy as np

def get_with_default(a, indices, default=0):
    # Ensure inputs are arrays
    a = np.asarray(a)
    indices = tuple(np.broadcast_arrays(*indices))
    if len(indices) <= 0 or len(indices) > a.ndim:
        raise ValueError('invalid number of indices.')
    # Make mask of indices out of bounds
    mask = np.zeros(indices[0].shape, np.bool)
    for ind, s in zip(indices, a.shape):
        mask |= (ind < 0) | (ind >= s)
    # Only do masking if necessary
    n_mask = np.count_nonzero(mask)
    # Shortcut for the case where all is masked
    if n_mask == mask.size:
        return np.full_like(a, default)
    if n_mask > 0:
        # Ensure index arrays are contiguous so masking works right
        indices = tuple(map(np.ascontiguousarray, indices))
        for ind in indices:
            # Replace masked indices with zeros
            ind[mask] = 0
    # Get values
    res = a[indices]
    if n_mask > 0:
        # Replace values of masked indices with default value
        res[mask] = default
    return res

# Test
print(get_with_default(
    np.array([[1,2,3],[4,5,6]]),
    (np.array([0, 0, 1, 1, 2, 2]), np.array([1, 2, 2, 3, 3, 5])),
    13
))
# [ 2  3  6 13 13 13]

答案 22 :(得分:1)

将Clickable设置为false在第一次双击时不起作用,但后续双击会被阻止。就好像第一次加载点击委托更慢,第二次点击在第一次完成之前被捕获。

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

答案 23 :(得分:1)

  

我们可以使用刚刚同步的按钮:

@Override
public void onClick(final View view) {
    synchronized (view) {

        view.setEnabled(false);

        switch (view.getId()) {
            case R.id.id1:
                ...
                break;
            case R.id.id2:
                ...
                break;
                ...
        }

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

            @Override
            public void run() {
                view.setEnabled(true);
            }
        }, 1000);
    }
}
  

祝你好运)

答案 24 :(得分:1)

您可以使用此方法。通过使用后延迟,您可以照顾双击事件。

void debounceEffectForClick(查看视图){

    view.setClickable(false);

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

        }
    }, 500);
}

答案 25 :(得分:1)

我使用两个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);

答案 26 :(得分:1)

带有 Kotlin 扩展功能:

fun View.onSingleClick(action: (v: View) -> Unit) {
    setOnClickListener(object : View.OnClickListener {
        override fun onClick(v: View) {
            isEnabled = false
            action(v)
            postDelayed({ isEnabled = true }, 700)
        }
    })
}

用法:

button.onSingleClick { myAction() }

答案 27 :(得分:1)

您也可以使用rx bindings by 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
                });

//注意:在这种情况下忽略对象v,我想永远。

答案 28 :(得分:1)

Adding to Jim's answer the code can be made more concise:

fun View.setOnSingleClick(onClick: () -> Unit) {
    var lastClickTime = 0L
    setOnClickListener {
        if (currentTimeMillis() > lastClickTime + 750) onClick()
        lastClickTime = currentTimeMillis()
    } 
}

用法:

aView.setOnSingleClick {  }

答案 29 :(得分:1)

试试这个,它正在运作:

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

答案 30 :(得分:1)

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

答案 31 :(得分:1)

下面的代码将阻止用户在几分之一秒内多次单击,并且仅在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();
    }
}

答案 32 :(得分:1)

    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            //to prevent double click
            button.setOnClickListener(null);
        }
    });

答案 33 :(得分:0)

这是一个 OnClickListener proxy,它根据 qezt's answer 阻止连续点击。

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

public class MultiClickGuard implements View.OnClickListener {    

    private long mLastClickTime;

    private final int mThresholdMillis;
    private final View.OnClickListener mListener;

    public MultiClickGuard(View.OnClickListener listener, int thresholdMillis) {
        if (listener == null) {
            throw new NullPointerException("Null OnClickListener");
        }
        if (thresholdMillis < 0) {
            throw new IllegalArgumentException("Negative click threshold: " + thresholdMillis);
        }

        mListener = listener;
        mThresholdMillis = thresholdMillis;
    }

    @Override
    public void onClick(View v) {
        // Using a time threshold to prevent successive clicks.
        if (SystemClock.elapsedRealtime() - mLastClickTime < mThresholdMillis) {
            return;
        }
        mLastClickTime = SystemClock.elapsedRealtime();

        // Forward the click event to the *real* listener.
        mListener.onClick(v);
    }
}

使用示例

button.setOnClickListener(new MultiClickGuard(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // do something
    }
}, 1000));

button.setOnClickListener(new MultiClickGuard(v -> {...}, 1000));
button.setOnClickListener(new MultiClickGuard(v -> doSomething(), 1000));

如果您试图阻止启动多个 Activity 实例,请考虑指定启动模式:Understand Tasks and Back Stack,这是实现此目的的可靠方法。

如果您试图阻止打开一个对话框片段的多个实例,您可以检查片段管理器是否已经包含该对话框,例如getSupportFragmentManager().findFragmentByTag(tag)

答案 34 :(得分:0)

在科特林

button.setOnClickListener { 
    it?.apply { isEnabled = false; postDelayed({ isEnabled = true }, 400) //400 ms
    //do your work
}

答案 35 :(得分:0)

This解决方案简洁明了。

基本上,您只需防止应用中的基本样式发生双击即可,并在点击侦听器上实现标准。这就像在不同视图的同时具有触摸感的魅力一样。

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
...
<item name="android:splitMotionEvents">false</item>
<item name="android:windowEnableSplitTouch">false</item>
</style>

如果您的应用使用某种手势事件,那么这不是正确的答案。

答案 36 :(得分:0)

尝试使用此Kotlin扩展功能:

private var lastClickTime = 0L

fun View.click(action: () -> Unit) {
    setOnClickListener {
        if (SystemClock.elapsedRealtime() - lastClickTime < 600L)
            return@setOnClickListener
        lastClickTime = SystemClock.elapsedRealtime()
        action()
    }
}

它还可以防止同时点击应用的各个部分。

答案 37 :(得分:0)

将按钮设置为可单击是一次正确的方法,即在单击时将false设置为false,然后在希望再次使按钮可单击时将其设置为true。例如,请考虑以下情形:单击按钮进行服务调用,完成服务后,您要显示一个对话框。为此,单击按钮后,您可以设置setClickable(false),一旦服务响应,您将通过传递给自定义对话框的引用来执行setClicklable(true)。当对话框调用isShowing()时,您可以触发侦听器和setClicklable(true)。

答案 38 :(得分:0)

防止点击多个 btns

使用:

private val disposables = CompositeDisposable()
private val clickInteractor = ClickInteractor(disposables)
...
button1.setOnClickListener{
     clickInteractor.click {
          Toast.makeText(context, "Btn1", Toast.LENGTH_LONG).show()
     }
}
button2.setOnClickListener{
     clickInteractor.click {
          Toast.makeText(context, "Btn2", Toast.LENGTH_LONG).show()
     }
}

ClickInteractor.kt:

class ClickInteractor constructor(disposables: CompositeDisposable) {
    private val performPublish = PublishSubject.create<ClickInteractorCallback>()

    init {
        performPublish
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.io())
            .throttleFirst(1, TimeUnit.SECONDS, Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnNext { callback ->
                callback.invoke()
            }
            .retry()
            .execute(disposables)
    }

    fun click(callback: ClickInteractorCallback) {
        performPublish.onNext(callback)
    }
}

typealias ClickInteractorCallback = () -> Unit

答案 39 :(得分:0)

  

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

答案 40 :(得分:0)

对于任何使用数据绑定的人:

@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()}"
                   ... />

答案 41 :(得分:0)

The Best and simple solution i found is 
1. to create a boolean and set as false (default) like
private boolean itemClicked = false;

/* for a safer side you can also declare boolean false in onCreate() also. */
and at onclick() method check 
2. if(!itemClicked)
{
itemClicked = true;
// rest of your coding functionality goes here of onClick method.
}
3. last step is to set boolean false in onResume()
@override
onResume()
{
super.onResume(0);
itemClicked = false;
}

答案 42 :(得分:0)

如果单击该按钮,您将打开一个新片段,只需将myMap.get("myObject1"); 添加到正在打开的新片段的根视图中。

答案 43 :(得分:0)

这是我的解决方案:

if (waitDouble) {
    waitDouble = false;
    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                sleep(300);
                if (waitDouble == false) {
                    waitDouble = true;
                    singleClick();  //singleClick
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    thread.start();
} else {//DoubleClick
    DoubleClick();
    waitDouble = true;
}

或另一种解决方案:

public class NoDoubleClickUtils {
    private static long lastClickTime;
    private final static int SPACE_TIME = 500;

    public static void initLastClickTime() {
        lastClickTime = 0;
    }

    public synchronized static boolean isDoubleClick() {
        long currentTime = System.currentTimeMillis();
        boolean isClick2;
        if (currentTime - lastClickTime > SPACE_TIME) {
            isClick2 = false;
        } else {
            isClick2 = true;
        }
        lastClickTime = currentTime;
        return isClick2;
    }
}

答案 44 :(得分:0)

阻止UI线程时,单击事件排队。在按钮单击事件上,请尽快更改为后台任务,以避免点击事件排在彼此后面。

在activity类中声明一个volatile布尔值或锁:

private volatile boolean saving = false;

创建一个带有onClickListener的按钮,该按钮通过保存并启动后台任务来完成工作:

saveButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View view) {
        if (!saving) {
            saving = true;
            new SaveAsyncTask().execute();
        }
    }
});

创建一个内部SaveAsyncTask类以在后台完成工作:

class SaveAsyncTask extends AsyncTask {

    @Override
    protected Object doInBackground(Object[] objects) {
        // Do something here, simulate a 3 second task
        SystemClock.sleep(3000);
        saving = false;
        return null;
    }
}

答案 45 :(得分:0)

我需要用片段进行woking,只需要设置一个标志来控制点击:我只想要第一个,其他人无法访问监听器

private boolean flag = true;

...

@Override
public void onClick(View view) {

    ...

    if (flag) {

        ...

        listener.onFragmentInteraction(Constants.MY_FRAGMENT, bundle);
        flag = false;
    }

    ...

}

希望它有用,如果不正确则纠正我

答案 46 :(得分:0)

只需2步,您就可以在应用程序的任何位置使用它。

<强>步骤1 即可。创建一个单身经理[避免多次点击]

package com.im.av.mediator;

import android.os.SystemClock;

import java.util.HashMap;

/**
 * Created by ShuHeng on 16/6/1.
 */
public class ClickManager {



    private HashMap<Integer,Long> laskClickTimeMap=new HashMap<Integer,Long>();
    public volatile static ClickManager mInstance =null;

    public static ClickManager getInstance(){
        if (mInstance == null) {
            synchronized(ClickManager.class) {
                if (mInstance == null) {
                    mInstance = new ClickManager();
                }
            }
        }
        return mInstance;
    }
   public boolean isClickable1s(Integer key){
       Long keyLong = laskClickTimeMap.get(key);
       if(keyLong==null){
           laskClickTimeMap.put(key,SystemClock.elapsedRealtime());
           return true;
       }else{
           if (SystemClock.elapsedRealtime() - keyLong.longValue() < 1000){
               return false;
           }else{
               laskClickTimeMap.put(key,new Long(SystemClock.elapsedRealtime()));
               return true;
           }
       }
   }
}  

<强>步骤2 即可。添加一行以避免多次单击。

@Override
public void onClick(View v) {
    // TODO Auto-generated method stub
    int id = v.getId();
    if (id == R.id.iv_back) {
        if(!ClickManager.getInstance().isClickable1s(R.id.iv_back))return;
        //do something
    } else if (id == R.id.iv_light) {
        if(!ClickManager.getInstance().isClickable1s(R.id.iv_light))return;
        //do something
    } else if (id == R.id.iv_camerarotate) {
        if(!ClickManager.getInstance().isClickable1s(R.id.iv_camerarotate))return;
           //do something
    } else if (id == R.id.btn_delete_last_clip) {
        if(!ClickManager.getInstance().isClickable1s(R.id.btn_delete_last_clip))return;
          //do something

    } else if (id == R.id.iv_ok) {
        if(!ClickManager.getInstance().isClickable1s(R.id.iv_ok))return;
        //do something
    }
}

答案 47 :(得分:0)

通用解决方案

@Override
        public void onClick(View v) {
            tempDisableButton(v);
            //all the buttons view..
        }

public void tempDisableButton(View viewBtn) {
        final View button = viewBtn;

        button.setEnabled(false);
        button.postDelayed(new Runnable() {
            @Override
            public void run() {
                button.setEnabled(true);
            }
        }, 3000);
    }

答案 48 :(得分:0)

如果按钮唯一做的就是启动新活动,问题可以通过&#34; singleTop&#34;来解决。激活启动模式,并在意图上设置FLAG_ACTIVITY_CLEAR_TOP。这个在复杂活动的层次结构中不起作用,但对于简单的树状应用程序结构是可行的。

答案 49 :(得分:0)

我更喜欢使用信号量块。它是线程安全的,不仅可以用于按钮。

代码示例很简单:

private UtilsSemaphore buttonSemaphore = new UtilsSemaphore();

public void onClick(View view)
{

    boolean isAllowed = buttonSemaphore.lock();

    if(!isAllowed)
    {
        return;
    }

    final View clickedButton = view;

    clickedButton.setEnabled(false);

    /* some code */

    buttonSemaphore.unlock();
    clickedButton.setEnabled(true);
}


public class UtilsSemaphore {

    public int counter = 0;

    public boolean lock()
    {
        int counterValue = ++counter;
        boolean isAllowed = counterValue < 2;

        if(!isAllowed)
        {
            unlock();
        }

        return isAllowed;
    }

    public void unlock()
    {
        --counter;
    }

}

答案 50 :(得分:0)

如果您不想(或不能)使用boolean标记或覆盖onClickListener,您还可以尝试在AndroidManifest.xml中使用android:launchMode="singleTop"声明您的活动。

它是如何工作的?

  • 如果活动的实例位于堆栈的顶部 - 新的 不会创建活动,而是调用onNewIntent()。
  • 活动可以有多个实例
  • 实例可以驻留在不同的任务中
  • 一个任务可以有多个实例

答案 51 :(得分:-3)

更优选的解决方案是,

onclick(){
  btn.setEnabled(false);
  btn.setClickable(false);
  //yourwork
  myWork();
}

myWork(){
 //your tasks.
 btn.setEnabled(true);
 btn.setClickable(true);
}

由于链接可以轻易忽略,我不得不一次又一次地重复这个