59

What's the best way to disable the touch events for all the views?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Gratzi
  • 4,633
  • 12
  • 42
  • 58

15 Answers15

61

Here is a function for disabling all child views of some view group:

 /**
   * Enables/Disables all child views in a view group.
   * 
   * @param viewGroup the view group
   * @param enabled <code>true</code> to enable, <code>false</code> to disable
   * the views.
   */
  public static void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) {
    int childCount = viewGroup.getChildCount();
    for (int i = 0; i < childCount; i++) {
      View view = viewGroup.getChildAt(i);
      view.setEnabled(enabled);
      if (view instanceof ViewGroup) {
        enableDisableViewGroup((ViewGroup) view, enabled);
      }
    }
  }
Community
  • 1
  • 1
peceps
  • 17,370
  • 11
  • 72
  • 79
  • 7
    @peceps unfortunately it does not work for fragments. For example if `ViewGroup` has a fragment child, added in a `FragmentTransaction` the `fragment` and its children wouldn't become disabled. – AlexAndro Mar 28 '13 at 12:27
  • @AlexAndro: Still I used method for `Fragment` added via `FrameLayout` and This worked very well. – Uniruddh Jun 12 '14 at 03:06
  • This solution assumes that all the views in the viewgroup are direct childs of the viewgroup. However, usually, that's not the case. – div May 28 '20 at 22:33
  • @div nope, there is a recursion in the solution for that case. However the solution has a flaw: the Views must respect `setEnabled()`/`isEnabled` - and many out there just ignore this... – ubuntudroid Aug 11 '22 at 19:02
21

Override the dispatchTouchEvent method of the activity and like this:

@Override
public boolean dispatchTouchEvent(MotionEvent ev){      
  return true;//consume
}

If you return true all touch events are disabled.

Return false to let them work normally

ThomasW
  • 16,981
  • 4
  • 79
  • 106
Ercan
  • 3,705
  • 1
  • 22
  • 37
  • my Activity holds a RecyclerView, no matter if true or false is returned, if I overwrite the Methode all touch events are disables. Do you have any idea – Aiko West Apr 10 '19 at 07:05
  • 4
    @K.Dexter you might have forgot to call `super.dispatchTouchEvent(ev)` – Ercan Apr 11 '19 at 08:41
18

You could try:

your_view.setEnabled(false);

Which should disable the touch events.

alternatively you can try (thanks to Ercan):

@Override
public boolean dispatchTouchEvent(MotionEvent ev){      
  return true;//consume
}

or

public boolean dispatchTouchEvent(MotionEvent ev) {
    if(!onInterceptTouchEvent()){
        for(View child : children){
            if(child.dispatchTouchEvent(ev))
                return true;
        }
    }
    return super.dispatchTouchEvent(ev);
}
OWADVL
  • 10,704
  • 7
  • 55
  • 67
13

This piece of code will basically propagate this event to the parent view, allowing the touch event, if and only if the inProgress variable is set to false.

private boolean inProgress = false;

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (!inProgress)
        return super.dispatchTouchEvent(ev);
    return true;
 }
noloman
  • 11,411
  • 20
  • 82
  • 129
Bruno Horta
  • 201
  • 3
  • 3
  • Welcome to Stack Overflow! I've edited your answer; by indenting code by 4 spaces, it is put in `code markdown`. In general, when posting answers here, it is best to provide a little explanation, in addition to the code. – S.L. Barth is on codidact.com Sep 15 '16 at 09:30
  • 2
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – J. Chomel Sep 16 '16 at 07:29
  • I'd invert the `if` statement to avoid the unnecessary negative. Logically equivalent, but reduces the possibility of errors (the not sign, '!' is easy to miss). – SMBiggs Mar 12 '20 at 07:50
10

Use this. returning true will indicate that the listener has consumed the event and android doesn't need to do anything.

view.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return true;
    }
});
Abhishek
  • 2,295
  • 24
  • 28
  • 1
    This answer will allow you to disable touch events while leaving the view enabled, if you ever have a weird use case like I did that needs that. – Dave S May 18 '18 at 01:47
  • Useful in case of using drag and drop (my case). Thanks! – Jakub Kostka Oct 05 '19 at 10:05
  • Works on a view. Not on a viewgroup. Child views in a viewgroup are still able to receive click events. – div May 28 '20 at 22:23
6

The easiest way to do this is

private fun setInteractionDisabled(disabled : Boolean) {
  if (disabled) {
    window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
  } else {
    window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
  }
} 
droid256
  • 404
  • 5
  • 15
Shivam Dawar
  • 493
  • 7
  • 6
5

What about covering a transparent view over all of your views and capturing all touch event?

Yudi
  • 59
  • 1
  • 1
  • I'm also thinking about that right now, but wouldn't it be difficult to cover everything from a child view? Wouldn't it be constrained to the size of its direct parent? – peedee Mar 23 '15 at 09:29
  • Nice answer but I had no idea what this meant-`capturing all touch event`. It led me in the right directions and it simply means making your view `clickable` explained here: https://stackoverflow.com/a/50299156/4833705 – Lance Samaria Jun 13 '23 at 08:54
4
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                     WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
krock
  • 28,904
  • 13
  • 79
  • 85
Indra K
  • 37
  • 1
  • 6
4

In Kotlin:

fun View.setEnabledRecursively(enabled: Boolean) {
    isEnabled = enabled
    if (this is ViewGroup)
        (0 until childCount).map(::getChildAt).forEach { it.setEnabledRecursively(enabled) }
}

// usage
import setEnabledRecursively

myView.setEnabledRecursively(false)
yanchenko
  • 56,576
  • 33
  • 147
  • 165
3

I made this method, which works perfect for me. It disables all touch events for selected view.

public static void disableView(View v) {

    v.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return true;
        }
    });

    if (v instanceof ViewGroup) {
        ViewGroup vg = (ViewGroup) v;
        for (int i = 0; i < vg.getChildCount(); i++) {
            View child = vg.getChildAt(i);
            disableView(child);
        }
    }
}
jan hruska
  • 249
  • 1
  • 9
2

It may not be possible for the whole application. You will have to override onTouchEvent() for each view and ignore the user inputs.

Rajath
  • 11,787
  • 7
  • 48
  • 62
0

Per your comment:

i just want to be able to disable the views of the current activity at some point

you seem to want to disable all touch for the current activity regardless of the view touched.

Returning true from an override of Activity.dispatchTouchEvent(MotionEvent) at the appropriate times will consume the touch and effectively accomplish this. This method is the very first in a chain of touch method calls.

Ken
  • 30,811
  • 34
  • 116
  • 155
0

In case you want to disable all the views in a specific layout, one solution is adding a cover ( a front view that fills up the whole layout ) to consume all the touch events, so that no events would be dispatched to other views in that layout.

Specifically, you first need to add a view to the layout in xml file ( note that it should be placed after all the other views ), like

<FrameLayout>
  ... // other views
  <View
    android:id="@+id/vCover"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
  />
</FrameLayout>

then, remember to set click listener to that view in your code so that it will consume touch events, like

override fun onCreate(savedInstanceState: Bundle?) {
  viewBinding.vCover.setOnClickListener {}
}

That's all you need.

At the point you want to enable all the view, just gone the cover.

-1

This worked for me, I created an empty method and called it doNothing.

   public void doNothing(View view)
{

}

Then called this method from onClick event on all the objects I wanted to disable touch event. android:onClick="doNothing"

When the click or touch event is fired nothing is processed.

Kizito Ikapel
  • 69
  • 1
  • 6
-3

One more easier way could be disabling it through layout (i.e. .xml) file: Just add

 android:shouldDisableView="True"

for the view you want disable touch events.

ByteWelder
  • 5,464
  • 1
  • 38
  • 45
BhanuSingh
  • 118
  • 1
  • 2
  • 15