如何避免在android中同时单击多个按钮?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20971484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:44:57  来源:igfitidea点击:

How to avoid multiple button click at same time in android?

androidbuttononclicklistener

提问by Murali Ganesan

I'm using two button in view. While clicking two button simultaneously it will goes to different activity at a time. How to avoid this?

我正在使用两个按钮。同时单击两个按钮时,它将一次转到不同的活动。如何避免这种情况?

I have tried like this, But its not working please save....

我试过这样,但它不工作,请保存....

public class MenuPricipalScreen extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.menu_principal_layout);


    findViewById(R.id.imageView2).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub

            disable(findViewById(R.id.imageView3));

            Intent intent = new Intent(MenuPricipalScreen.this,
                    SelectYourLanguageVideo.class);
            startActivity(intent);
        }
    });
    findViewById(R.id.imageView3).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub

            disable(findViewById(R.id.imageView2));

            Intent intent = new Intent(MenuPricipalScreen.this,
                    CategoryScreen.class);
            intent.putExtra("request", "false");
            startActivity(intent);
        }
    });

}

 @Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    ((ImageView) findViewById(R.id.imageView3)).setEnabled(true);
    ((ImageView) findViewById(R.id.imageView2)).setEnabled(true);
    ((ImageView) findViewById(R.id.imageView3)).setClickable(true);
    ((ImageView) findViewById(R.id.imageView2)).setClickable(true);
    ((ImageView) findViewById(R.id.imageView3)).setFocusable(true);
    ((ImageView) findViewById(R.id.imageView2)).setFocusable(true);
}

 private void disable(View v) {
    Log.d("TAG", "TAG" + v.getId());
    v.setEnabled(false);
    v.setClickable(false);
    v.setFocusable(false);
}
}

Thanks,

谢谢,

回答by Shivanand Darur

The standard way to avoid multiple clicks is to save the last clicked time and avoid the other button clicks within 1 second (or any time span). Example:

避免多次点击的标准方法是保存上次点击时间并避免在 1 秒(或任何时间跨度)内点击其他按钮。例子:

// Make your activity class to implement View.OnClickListener
public class MenuPricipalScreen extends Activity implements View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // setup listeners.
        findViewById(R.id.imageView2).setOnClickListener(MenuPricipalScreen.this);
        findViewById(R.id.imageView3).setOnClickListener(MenuPricipalScreen.this);
        ...
     }

    .
    .
    .

    // variable to track event time
    private long mLastClickTime = 0;

    // View.OnClickListener.onClick method defination

    @Override
    public void onClick(View v) {
        // Preventing multiple clicks, using threshold of 1 second
        if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) {
            return;
        }
        mLastClickTime = SystemClock.elapsedRealtime();

        // Handle button clicks
        if (v == R.id.imageView2) {
            // Do your stuff.
        } else if (v == R.id.imageView3) {
            // Do your stuff.
        }
        ...
    }

    .
    .
    .

 }

回答by demir

you can disable the multi-touch on your app by using this android:splitMotionEvents="false"and android:windowEnableSplitTouch="false"in your theme.

您可以通过使用此禁用您的应用程序的多点触控android:splitMotionEvents="false",并android:windowEnableSplitTouch="false"在你的主题。

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

回答by Martin Marconcini

Cheap Solution:

便宜的解决方案:

You don't have a correct separation of concerns (MVP or any flavor) so you put your code in your Activity/Fragment

您没有正确的关注点分离(MVP 或任何风格),因此您将代码放在 Activity/Fragment 中

  • If you can't handle this the correct way, at least do not use non-deterministic solutions (like a timer).

  • Use the tools you already have, say you have this code:

  • 如果您不能以正确的方式处理这个问题,至少不要使用非确定性的解决方案(如计时器)。

  • 使用您已有的工具,假设您有以下代码:



//Somewhere in your onCreate()
Button myButton = findViewById… 
myButton.setOnClickListener(this);

// Down below…
@Override
public void onClick(View view) {
     if (myButton.isEnabled()) {
        myButton.setEnabled(false);
        // Now do something like…
        startActivity(…);
    }
}

Now… in a completely different place in your logic, like… for example, your onCreate or your onResume or anywherewhere you know you want your button working again…

现在......在你的逻辑中完全不同的地方,比如......例如,你的 onCreate 或你的 onResume 或任何你知道你希望你的按钮再次工作的地方......

 myButton.setEnabled(true);

“More Modern” Approach:

“更现代”的方法:

  1. Do the same, but put the logic in your Presenter.
  2. Your presenter will decide if the “button” action has been triggered.
  3. Your presenter will tell its “view”: enableMyButton();or disableMyButton()depending.
  4. Your View will do the right thing.
  5. you know… basic separation of concerns.
  1. 做同样的事情,但把逻辑放在你的 Presenter 中。
  2. 您的演示者将决定是否触发了“按钮”操作。
  3. 您的演示者将讲述其“观点”:enableMyButton();disableMyButton()视情况而定。
  4. 您的视图会做正确的事情。
  5. 你知道……基本的关注点分离。

WHY “enabled(true/false)”?

为什么“启用(真/假)”?

Because it's built in. Because the button will respect its state (and if you have a correct state list, it will change appearance for you, and because it will always be what you expect). Also, because it's easier to test a presenter full of mocks, than a full activity that can grow forever in code.

因为它是内置的。因为按钮会尊重它的状态(如果你有一个正确的状态列表,它会为你改变外观,因为它总是你所期望的)。此外,因为测试一个充满模拟的演示者比一个可以在代码中永远增长的完整活动更容易。

回答by Siyabonga Dube

The simple way to do it in Kotlin is to use:

在 Kotlin 中执行此操作的简单方法是使用:

//When you need to disable the button
  btn.isEnabled = false

//When you need to enable the button again 
  btn.isEnabled = true

回答by Salah Hammouda

for any one using data-binding :

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

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

回答by Jason Grife

Here's a class that debounce's clicks for Viewand MenuItem.

下面是一类反跳的点击次数ViewMenuItem

import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;

/**
 * Debounce's click events to prevent multiple rapid clicks.
 * <p/>
 * When a view is clicked, that view and any other views that have applied {@link #shareDebounce} to them,
 * will have subsequent clicks ignored for the set {@link #DEBOUNCE_DURATION_MILLIS duration}.
 */
public final class ClickEvent {
    private static final long DEBOUNCE_DURATION_MILLIS = 1000L;
    private long debounceStartTime = 0;

    /**
     * Wraps the provided {@link OnClickListener OnClickListener} in a {@link ClickEvent}
     * that will prevent multiple rapid clicks from executing.
     * <p/>
     * Usage:
     * <pre>View.setOnClickListener(ClickEvent.debounce((OnClickListener) v -> // click listener runnable))</pre>
     */
    public static OnClickListener debounce(@NonNull OnClickListener onClickListener) {
        return new ClickEvent().wrapOnClickListener(onClickListener);
    }

    /**
     * Wraps the provided {@link OnMenuItemClickListener OnMenuItemClickListener} in a
     * that will prevent multiple rapid clicks from executing.
     * <p/>
     * Usage:
     * <pre>MenuItem.setOnClickListener(ClickEvent.debounce((OnMenuItemClickListener) v -> // click listener runnable))</pre>
     */
    public static OnMenuItemClickListener debounce(@NonNull OnMenuItemClickListener onClickListener) {
        return new ClickEvent().wrapOnClickListener(onClickListener);
    }

    /**
     * Allows the debounce to be shared between views to prevent multiple rapid clicks between views.
     * <p/>
     * Usage:
     * <pre>
     *     ClickEvent clickEvent = new ClickEvent();
     *     View1.setOnClickListener(clickEvent.shareDebounce((OnClickListener) v -> // click listener runnable for View1))
     *     View2.setOnClickListener(clickEvent.shareDebounce((OnClickListener) v -> // click listener runnable for View2))
     * </pre>
     */
    public OnClickListener shareDebounce(@NonNull OnClickListener listener) {
        return wrapOnClickListener(listener);
    }

    /**
     * Allows the debounce to be shared between views to prevent multiple rapid clicks between views.
     * Usage:
     * <pre>
     *     ClickEvent clickEvent = new ClickEvent();
     *     MenuItem1.setOnClickListener(clickEvent.shareDebounce((OnMenuItemClickListener) v -> // click listener runnable for MenuItem1))
     *     MenuItem2.setOnClickListener(clickEvent.shareDebounce((OnMenuItemClickListener) v -> // click listener runnable for MenuItem2))
     * </pre>
     */
    public OnMenuItemClickListener shareDebounce(@NonNull OnMenuItemClickListener listener) {
        return wrapOnClickListener(listener);
    }

    public void setDebounceStartTime() {
        debounceStartTime = SystemClock.elapsedRealtime();
    }

    public boolean isThrottled() {
        return SystemClock.elapsedRealtime() - debounceStartTime < DEBOUNCE_DURATION_MILLIS;
    }

    private OnClickListener wrapOnClickListener(@NonNull OnClickListener onClickListener) {
        if (onClickListener instanceof OnThrottledClickListener) {
            throw new IllegalArgumentException("Can't wrap OnThrottledClickListener!");
        }
        return new OnThrottledClickListener(this, onClickListener);
    }

    private OnMenuItemClickListener wrapOnClickListener(@NonNull OnMenuItemClickListener onClickListener) {
        if (onClickListener instanceof OnThrottledClickListener) {
            throw new IllegalArgumentException("Can't wrap OnThrottledClickListener!");
        }
        return new OnThrottledClickListener(this, onClickListener);
    }

    private static class OnThrottledClickListener implements OnClickListener, OnMenuItemClickListener {
        private final ClickEvent clickEvent;
        private OnClickListener wrappedListener;
        private OnMenuItemClickListener wrappedMenuItemClickLister;

        OnThrottledClickListener(@NonNull ClickEvent clickEvent, @NonNull OnClickListener onClickListener) {
            this.clickEvent = clickEvent;
            this.wrappedListener = onClickListener;
        }

        OnThrottledClickListener(@NonNull ClickEvent clickEvent, @NonNull OnMenuItemClickListener onClickListener) {
            this.clickEvent = clickEvent;
            this.wrappedMenuItemClickLister = onClickListener;
        }

        @Override
        public void onClick(View v) {
            if (clickEvent.isThrottled()) {
                return;
            }
            wrappedListener.onClick(v);
            clickEvent.setDebounceStartTime();
        }

        @Override
        public boolean onMenuItemClick(MenuItem menuItem) {
            if (clickEvent.isThrottled()) {
                return false;
            }
            clickEvent.setDebounceStartTime();
            return wrappedMenuItemClickLister.onMenuItemClick(menuItem);
        }
    }
}

回答by Rex Lam

You can try my tiny library, it provides what exactly you want using same approach as Shivanand' solution. https://github.com/RexLKW/SClick

你可以试试我的小库,它使用与 Shivanand 的解决方案相同的方法提供了你想要的东西。 https://github.com/RexLKW/SClick

回答by Ranjith Kumar

For Kotlin users

对于 Kotlin 用户

object AppUtil {

var mLastClickTime=0L

fun isOpenRecently():Boolean{
    if (SystemClock.elapsedRealtime() - mLastClickTime < 1000){
        return true
    }
    mLastClickTime = SystemClock.elapsedRealtime()
    return false
}
}

In your Activity or Fragment or anywhere

在您的 Activity 或 Fragment 或任何地方

just add this one line condition

只需添加这一行条件

 if(isOpenRecently()) return

example:

例子:

fun startHomePage(activity: Activity){
     if(isOpenRecently()) return //this one line enough 
    val intent= Intent(activity,MainActivity::class.java)
    activity.startActivity(intent)

}

回答by TheAnimatrix

A "Better" Practice is to use the onClickListener like this ->

“更好”的做法是像这样使用 onClickListener ->

OnClickListener switchableListener = new OnClickListener(@Override
    public void onClick(View arg0) {
        arg0.setOnClickListener(null);

        (or) use the view directly as a final variable in case of errors
             ex :
                     textView.setOnClickListener(null);


         // Some processing done here

         Completed , enable the onclicklistener arg0.setOnClickListener(switchableListener);
    });

This should fix the problem and its quite a simple way of handling things

这应该可以解决问题,并且是一种非常简单的处理方式

回答by Gustavo Baiocchi Costa

For Xamarin users, I have created a solution that subclasses the button class:

对于 Xamarin 用户,我创建了一个子类化按钮类的解决方案:

using Android.Content;
using Android.Runtime;
using Android.Util;
using Android.Widget;
using System;
using System.Threading.Tasks;

namespace MyProject.Droid.CustomWidgets
{
    public class ButtonSingleClick : Button
    {
        private bool _clicked = false;
        public int _timer = 700;
        public new EventHandler Click;

        protected ButtonSingleClick(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        {
        }

        public ButtonSingleClick(Context context) : base(context)
        {
            base.Click += SingleClick;
        }

        public ButtonSingleClick(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            base.Click += SingleClick;
        }

        public ButtonSingleClick(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
        {
            base.Click += SingleClick;
        }

        public ButtonSingleClick(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
        {
            base.Click += SingleClick;
        }

        private void SingleClick(object sender, EventArgs e)
        {
            if (!_clicked)
            {
                _clicked = true;

                Click?.Invoke(this, e);

                Task.Run(async delegate
                {
                    await Task.Delay(_timer);
                    _clicked = false;
                });
            }
        }
    }
}