Android-同时检测父视图和子视图的触摸事件

5

目前我的应用程序布局如下:

       LinearLayout
            ----Button
               ----ScrollView
                  ----RelativeLayout
                     ----EditText

我创建了一个透明的LinearLayout,实现了OnTouchListener接口,在OnTouch()方法中返回了false。这样,所有的控件都被移动到子元素下面。但是在LinearLayout上,我无法处理ACTION_MOVE事件,因为该布局没有消耗MotionEvent对象。是否有办法可以检测父视图和子视图上的所有触摸事件?
2个回答

4

根据我的经验,不建议重写dispatchTouchEvent()方法,因为它比较难控制。我建议使用onInterceptTouchEvent()方法。但是,Android不支持重写该选项。您可以通过创建自己的View来劫持它,下面是一个继承自RelativeLayout的代码片段:

public class InterceptTouchRelativeLayout extends RelativeLayout{

public interface OnInterceptTouchListener{
    boolean onInterceptTouch(MotionEvent ev);
}

private OnInterceptTouchListener onInterceptTouchListener;

public InterceptTouchRelativeLayout(Context context) {
    super(context);
}

public InterceptTouchRelativeLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public InterceptTouchRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return onInterceptTouchListener.onInterceptTouch(ev);
}

public void setOnInterceptTouchListener(OnInterceptTouchListener onInterceptTouchListener) {
    this.onInterceptTouchListener = onInterceptTouchListener;
}

并像往常一样使用它,

myView.setOnInterceptTouchListener(new InterceptTouchRelativeLayout.OnInterceptTouchListener() {
        @Override
        public boolean onInterceptTouch(MotionEvent ev) {
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:
                    // Parent didn't steal this touch event if return false this case.
                    return false;

                case MotionEvent.ACTION_MOVE:
                    // Parent didn't steal this touch event if return false this case.
                    return false;

                case MotionEvent.ACTION_UP:
                    // Parent didn't steal this touch event if return false this case. However, please notice, it's too late for the parent to steal this touch event at this time, it won't work anymore.
                    return true;
            }

            return false;
        }
    });

无论如何,我的建议是更多地研究视图/视图组控件的触摸事件流。以下是onInterceptTouchEvent()的工作原理解释,供您参考:
当我们在父视图的子视图位置触摸时,如果在ACTION_DOWN时返回false,将被认为父视图尚未夺取此触摸事件,并检查其子视图是否已实现onTouch()。因此,只要子视图不调用requestDisallowInterceptTouchEvent(true),父视图仍然可以在onInterceptTouchEvent()中处理此触摸事件,而子视图可以在其自己的onTouch()事件中处理同一触摸事件。但是,有时您需要考虑处理父视图的onTouch()事件,以防没有子视图处理触摸事件,这样父视图就可以处理它。

1
你可以通过在布局中重写 dispatchTouchEvent 来实现这一点。
public class MyFrameLayout extends LinearLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
        // do what you need to with the event, and then...
        return super.dispatchTouchEvent(e);
    }
}

然后使用该布局替换通常的FrameLayout:
    <com.example.android.MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:padding="10dip"
        android:id="@+id/rootview">

  ...

如果您需要防止子视图接收事件,也可以完全跳过超级调用,但我认为这种情况很少见。

此答案基于Romain guy参考资料


我已经尝试过这个,但是dispatchTouchEvent仅在第一次调用。 之后,MotionEvent对象被任何子布局消耗,不再调用。 - N Kaushik
你想在父组件和子组件中都处理这个事件吗? - Kartheek
是的,我需要在两个布局中处理。实际上,我想要从外部活动获取所有ACTION_MOVE、UP、DOWN事件。 - N Kaushik
我将其用作包装器FrameLayout,覆盖了内联方法,然后将实际膨胀的视图添加到其中。效果很棒! - mike.adc

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