小智 327
单击时保存最后单击时间可以防止出现此问题.
即
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
}
}
Run Code Online (Sandbox Code Playgroud)
Com*_*are 74
禁用该按钮,setEnabled(false)直到用户再次单击它是安全的.
jin*_*i11 46
我的解决方案是
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);
}
}
Run Code Online (Sandbox Code Playgroud)
用法与OnClickListener类似,但改为覆盖onSingleClick():
mTextView.setOnClickListener(new OnSingleClickListener() {
@Override
public void onSingleClick(View v) {
if (DEBUG)
Log.i("TAG", "onclick?");
}
};
Run Code Online (Sandbox Code Playgroud)
Ken*_*Ken 39
如果您在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;
}
}
Run Code Online (Sandbox Code Playgroud)
用法与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);
Run Code Online (Sandbox Code Playgroud)
Yvg*_*gen 26
您可以使用Kotlin Extension Functions和RxBinding以非常好的方式完成它
fun View.clickWithDebounce(debounceTime: Long = 600L, action: () -> Unit): Disposable =
RxView.clicks(this)
.debounce(debounceTime, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { action() }
Run Code Online (Sandbox Code Playgroud)
要么
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()
}
})
}
Run Code Online (Sandbox Code Playgroud)
然后只是:
View.clickWithDebounce{ Your code }
Run Code Online (Sandbox Code Playgroud)
Win*_*der 18
该ķ最瘦的科特林惯用方式:
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))
}
Run Code Online (Sandbox Code Playgroud)
用法:
button.setOnSingleClickListener { ... }
Run Code Online (Sandbox Code Playgroud)
或者添加一个用于控制油门的参数
class OnClickListenerThrottled(private val block: () -> Unit, private val wait: Long) : View.OnClickListener {
private var lastClickTime = 0L
override fun onClick(view: View) {
if (SystemClock.elapsedRealtime() - lastClickTime < wait) {
return
}
lastClickTime = SystemClock.elapsedRealtime()
block()
}
}
/**
* A throttled click listener that only invokes [block] at most once per every [wait] milliseconds.
*/
fun View.setOnClickListenerThrottled(block: () -> Unit, wait: Long = 1000L) {
setOnClickListener(OnClickListenerThrottled(block, wait))
}
Run Code Online (Sandbox Code Playgroud)
用法:
button.setOnClickListenerThrottled(block = { /** some action */})
Run Code Online (Sandbox Code Playgroud)
Mud*_*sar 11
我也运行类似的问题,我正在显示一些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);
}
Run Code Online (Sandbox Code Playgroud)
您可以根据您的要求更改时间.这种方法适合我.
小智 6
我知道这是一个老问题,但是我分享了发现的最佳解决方案来解决这个常见问题
btnSomeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Prevent Two Click
Utils.preventTwoClick(view);
// Do magic
}
});
Run Code Online (Sandbox Code Playgroud)
在另一个文件中,例如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);
}
Run Code Online (Sandbox Code Playgroud)
我的解决方案是尝试使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
并使用如下:
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
}
}
});
Run Code Online (Sandbox Code Playgroud)
更新: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)
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
在科特林
button.setOnClickListener {
it?.apply { isEnabled = false; postDelayed({ isEnabled = true }, 400) } //400 ms
//do your work
}
Run Code Online (Sandbox Code Playgroud)
在我的情况下,我使用按钮视图,它太快了点击.只需禁用可点击并在几秒钟后再次启用它...
基本上我做了一个包装你的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);
}
}
Run Code Online (Sandbox Code Playgroud)
并调用它只需这样做:
mMyButton.setOnClickListener(new OnClickRateLimitedDecoratedListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doSomething();
}
}));
Run Code Online (Sandbox Code Playgroud)
或者提供你自己的延迟:
mMyButton.setOnClickListener(new OnClickRateLimitedDecoratedListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doSomething();
}
},1000));
Run Code Online (Sandbox Code Playgroud)
更新:现在RxJava非常流行,现在已经过时了.正如其他人所提到的,在android中我们可以使用节流来减慢点击次数.这是一个例子:
RxView.clicks(myButton)
.throttleFirst(2000, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe {
Log.d("i got delayed clicked")
}
}
Run Code Online (Sandbox Code Playgroud)
你可以使用这个库: implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
Click Guard适用于黄油刀
ClickGuard.guard(mPlayButton);
Run Code Online (Sandbox Code Playgroud)
如果有人仍在寻找简短答案,则可以使用以下代码
private static long mLastClickTime = 0;
if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) { // 1000 = 1second
return;
}
mLastClickTime = SystemClock.elapsedRealtime();
Run Code Online (Sandbox Code Playgroud)
if statement每当用户单击时,此代码都会放入View within 1 second,然后return;将启动,而其他代码将不会启动。
我们可以使用刚刚同步的按钮,如:
示例 #1(Java)
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
Example #2 (kotlin) 使用同步
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
祝你好运)
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)
}
}
Run Code Online (Sandbox Code Playgroud)
在基类中创建一个函数,否则
fun View.setSafeOnClickListener(onSafeClick: (View) -> Unit) {val safeClickListener = SafeClickListener {
onSafeClick(it)
}
setOnClickListener(safeClickListener)
}
Run Code Online (Sandbox Code Playgroud)
并在按钮单击时使用
btnSubmit.setSafeOnClickListener {
showSettingsScreen()
}
Run Code Online (Sandbox Code Playgroud)
下面的代码将阻止用户在几分之一秒内点击多次,并且只允许在 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();
}
}
Run Code Online (Sandbox Code Playgroud)
我的解决方案(科特林):
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)
}
Run Code Online (Sandbox Code Playgroud)
使用 :
button.apply {
setOnDebouncedClickListener {
//your action on click
}
}
Run Code Online (Sandbox Code Playgroud)
具有 Kotlin 扩展功能:
fun View.onSingleClick(action: (v: View) -> Unit) {
setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
isClickable = false
action(v)
postDelayed({ isClickable = true }, 700)
}
})
}
Run Code Online (Sandbox Code Playgroud)
用法:
button.onSingleClick { myAction() }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
115761 次 |
| 最近记录: |