Android: 如何防止触摸事件从视图传递到下面的视图?

82

具体来说,使用下面的代码,有没有一种方法可以修改它,使得在这个新创建的视图下的活动不接收任何手势?

View v1 = new View(this);    
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
 1000,
 50,
 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
 PixelFormat.OPAQUE);

params.gravity = Gravity.BOTTOM;
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
wm.addView(v1, params);
8个回答

109

在具有顶部位置的视图中添加一个onTouchEvent方法,然后返回true。True将告诉事件冒泡机制该事件已被消耗,因此防止事件冒泡到其他视图。

protected boolean onTouchEvent (MotionEvent me) {
    return true;
}

对于v1,您需要进行导入:

import android.view.View.OnTouchListener;

然后设置 onTouchListener:

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

1
伟大的解决方案,完美地适合这个问题。需要注意的是,它并不能阻止底层视图从物理键盘接收输入(这意味着如果用户使用带有物理光标键的手机,仍然可以玩弄伪禁用组件)。 - Rick77

78

从代码中

View v1 = new View(this);   
v1.setClickable(true);
v1.setFocusable(true);

来自xml

<View
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="My button"
    android:focusable="true"
    android:clickable="true"/>

这将防止触摸和点击事件被传递到停留在您视图下方的视图。
或者,如果您膨胀了View,那么可以在 .xml 文件中添加 android:clickable="true"


3
请注意,这可能会导致点击触摸动画传递到视图的第一个可聚焦元素。在我的情况下,我有一个SeekBar作为可点击视图的子元素,无论在哪里按下都会导致SeekBar的波纹动画启动。 - Stephen Kidson
2
我认为这是最好的解决方案,因为它可以直接从XML中完成。 - Jacques Giraudel
这个有效。在Kotlin/Java中不需要创建onTouchListener。 - coolcool1994

27

你也可以这样做。你可以将触摸监听器设置到子视图中,然后在onTouch()事件中,你可以使用我从https://stackoverflow.com/revisions/19311197/1答案中复制的代码来阻止父视图的拦截触摸事件

View v = findViewById(R.id.sample_view); v.setOnTouchListener(new
OnTouchListener() {
    // Setting on Touch Listener for handling the touch inside ScrollView
    @Override
    public boolean onTouch(View v, MotionEvent event) {
    // Disallow the touch request for parent scroll on touch of child view
    v.getParent().requestDisallowInterceptTouchEvent(true);
    return false;
    } });

1
这对我解决了一个recyclerview嵌套在另一个具有相同滚动方向的recyclerview中且快速滚动器无法工作的问题。在快速滚动器的onTouch事件中调用parent.requestDisallowInterceptTouchEvent(true)解决了这个问题。 - leegor

19

你可以像下面这样添加一个视图,但确保这是你在xml中添加的最后一个视图。xml中的最后一个项目是覆盖在它下面的所有其他视图之上的项目。

<View
        android:id="@+id/blocking_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#AA666666"
        android:clickable="true"
        android:focusable="true"
        android:visibility="visible"/>

3
“clickable”是重点。但是,即使您的布局位于所有其他内容的顶部(也可以被包含在内),并设置为“match_parent”,它也不会覆盖工具栏,这意味着工具栏上的按钮仍然可以被点击。 - Neph
这是一个可行的解决方案,关键是要为此阻塞器设置最高的ELEVATION。 - Владислав Шестернин

4
你只需要调用即可完成所有操作。
arg0.getParent().requestDisallowInterceptTouchEvent(true);

在您的onTouch函数开头添加以下代码。例如 -
    @Override
    public boolean onTouch(View arg0, MotionEvent arg1) {
        arg0.getParent().requestDisallowInterceptTouchEvent(true);
        switch(arg1.getActio){
        }

        return false; 

     }

3

我认为最好的方法是添加一个触摸事件,并设置返回值True

如下所示:

  someView.setOnTouchListener(object: View.OnTouchListener {
        override fun onTouch(v: View?, event: MotionEvent?): Boolean{
            return true
        }

    })

返回 True 意味着顶部视图正在处理触摸事件,无需将触摸事件移交给其他相关视图。


2

虽然我有点晚了,但我认为这个被接受的解决方案并不是很好。这里有一个静态方法,它接受任意数量的视图并禁用此事件冒泡。这在API 17+(更低尚未测试)中100%可行。

public static void disableEventBubbling(View... views){
    for(View view : views){
        if(view != null){
            view.setOnTouchListener(new View.OnTouchListener(){
               @Override
                public boolean onTouch(View view, MotionEvent event){
                    view.getParent().requestDisallowInterceptTouchEvent(true);
                    return false;
                }
            });
        }
    }
}

你可以为任何类型的事件添加一个case,或者你可以摆脱switch语句,并将默认情况下的case变成触摸监听器内唯一的行。


-2
只需将点击委托添加到顶部视图背景,这将阻止下面的视图接收触摸。
linear_layout_background.Click += delegate
            {
                // Ensures views underneath does not receive touch events
            };

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