禁用所有视图的触摸事件

59

如何禁用所有视图的触摸事件是最佳方法?


抱歉,请问这个更改的目标是什么?您可以编写一个递归过程,以更改每个视图的onTouchEvent()。 - carlovv
在你的root_layout上调用setEnabled(false); - ingsaurabh
你想让用户只在 Android 设备上使用按钮吗?;) - yosh
@T0X1C:这正是我要找的。但它不起作用。 - Gratzi
@yosh:我不想永久禁用它们。我只想在某个时候能够禁用当前活动的视图。 - Gratzi
@Gratzi,那个有什么问题?我的意思是你在做这件事时遇到了什么问题? - ingsaurabh
15个回答

61

这里有一个禁用某个视图组的所有子视图的函数:

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

7
很遗憾,它不适用于片段。例如,如果ViewGroup具有片段子项,在FragmentTransaction中添加了片段和其子项,则片段及其子项不会被禁用。 - AlexAndro
@AlexAndro:我仍然使用了针对通过FrameLayout添加的Fragment的方法,这个方法非常有效。 - uniruddh
这个解决方案假设视图组中的所有视图都是视图组的直接子级。然而,通常情况下并非如此。 - div
@div 不,对于那种情况,解决方案中存在递归。然而,该解决方案有一个缺陷:视图必须遵守 setEnabled()/isEnabled - 而许多人都忽略了这一点... - ubuntudroid

21

覆盖 Activity 的 dispatchTouchEvent 方法并按照如下方式:

@Override
public boolean dispatchTouchEvent(MotionEvent ev){      
  return true;//consume
}
如果您返回true,所有触摸事件都将被禁用。
如果您返回false,它们将正常工作。

我的Activity持有一个RecyclerView,无论返回true还是false,如果我重写该方法,则所有触摸事件都将被禁用。你有什么想法吗? - Aiko West
4
@K.Dexter你可能忘记调用super.dispatchTouchEvent(ev) - Ercan

18

你可以尝试:

your_view.setEnabled(false);

应该使用以下代码禁用触摸事件:

或者你可以尝试以下代码(感谢Ercan):

@Override
public boolean dispatchTouchEvent(MotionEvent ev){      
  return true;//consume
}
或者
public boolean dispatchTouchEvent(MotionEvent ev) {
    if(!onInterceptTouchEvent()){
        for(View child : children){
            if(child.dispatchTouchEvent(ev))
                return true;
        }
    }
    return super.dispatchTouchEvent(ev);
}

3
如果ListView是"your_view"的子ViewGroup,这段代码将无法在ListView元素上起效。 - Bijan
3
这不会禁用子视图的触摸功能。 - thumbmunkeys

13

这段代码基本上会将该事件传播到父视图,只有当 inProgress 变量设置为 false 时,才允许触摸事件。

private boolean inProgress = false;

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (!inProgress)
        return super.dispatchTouchEvent(ev);
    return true;
 }

欢迎来到 Stack Overflow!我已经编辑了您的答案;通过将代码缩进4个空格,它会被放置在“代码 markdown”中。通常,在此处发布答案时,最好除了代码外还提供一些解释。 - S.L. Barth
2
虽然这段代码片段可能解决了问题,但包括解释真的有助于提高您的帖子质量。请记住,您正在为未来的读者回答问题,而这些人可能不知道您的代码建议原因。 - J. Chomel
我会倒置 if 语句以避免不必要的否定。从逻辑上讲是等效的,但可以减少错误的可能性(取反符号“!”很容易被忽略)。 - SMBiggs

10

使用此方法。返回 true 将表示监听器已消耗该事件,Android 无需执行任何操作。

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

1
这个答案将允许您禁用触摸事件,同时保持视图启用,如果您有一个像我一样需要它的奇怪用例。 - Dave S
在使用拖放时非常有用(我的情况)。谢谢! - Jakub Kostka
仅适用于视图,而不适用于视图组。视图组中的子视图仍然能够接收点击事件。 - div

6

最简单的方法是这样做

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

5
什么是在所有视图上覆盖一个透明视图并捕获所有触摸事件?

我现在也在考虑这个问题,但是从子视图的角度来看,覆盖所有内容不会很困难吗?它不会受到其直接父视图大小的限制吗? - peedee
很好的回答,但我不知道这意味着什么,“capturing all touch event”。它给了我正确的方向,简单地意味着使你的视图可点击,在这里解释:https://dev59.com/YGoy5IYBdhLWcg3wnPWJ#50299156 - Lance Samaria

4
在 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)

4
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                     WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

3
我制作了这个方法,对我来说非常完美。它禁用了所选视图的所有触摸事件。
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);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接