如何在子视图组和父视图组触摸事件之间进行更改

Yve*_*omb 16 android parent-child touch-event interception android-view

我决定发布这个问题并回答这个问题的评论:
如何处理子视图中的点击,并触摸父ViewGroups?

我将粘贴评论:

假设我想仅仅为了处理一些孩子而覆盖触摸事件,我可以在这个函数中做些什么让它工作?我的意思是,对于一些孩子来说,它会像往常一样工作,对于一些人来说,父母视图将决定他们是否会接触到触摸事件.

所以问题是这样的:我如何阻止父母onTouchEvent()重写某些子元素onTouchEvent(),同时让它覆盖其他子元素?

Yve*_*omb 28

  1. onTouchEvents()嵌套视图组可由管理boolean onInterceptTouchEvent.

默认值为OnInterceptTouchEventfalse.

父母的onTouchEvent孩子在孩子面前被收到.如果OnInterceptTouchEvent返回false,则将链中的motion事件发送到子OnTouchEvent处理程序.如果它返回true,则父级将处理触摸事件.

但是,可能存在这样的情况:我们希望某些子元素管理OnTouchEvents而某些子元素由父视图(或可能是父视图的父元素)管理.

这可以通过多种方式进行管理.

  1. 可以OnInterceptTouchEvent通过实现requestDisallowInterceptTouchEvent来保护子元素免受父元素影响的一种方式.

public void requestDisallowInterceptTouchEvent(boolean disallowIntercept)

OnTouchEvent如果元素启用了事件处理程序,则会阻止任何父视图管理此元素.

  1. 如果OnInterceptTouchEvent为false,OnTouchEvent则将评估子元素.如果处理各种触摸事件的子元素中有方法,则禁用的任何相关事件处理程序都会将OnTouchEvent返回给父元素.

这个答案:
https://stackoverflow.com/a/13540006/3956566可以很好地显示触摸事件的传播方式:
parent -> child|parent -> child|parent -> child views.

  1. 另一种方法是从OnInterceptTouchEvent父级返回不同的值.

此示例取自ViewGroup中的"管理触摸事件" ,演示了OnTouchEvent在用户滚动时如何拦截子项.

4A.

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    /*
     * This method JUST determines whether we want to intercept the motion.
     * If we return true, onTouchEvent will be called and we do the actual
     * scrolling there.
     */


    final int action = MotionEventCompat.getActionMasked(ev);

    // Always handle the case of the touch gesture being complete.
    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
        // Release the scroll.
        mIsScrolling = false;
        return false; // Do not intercept touch event, let the child handle it
    }

    switch (action) {
        case MotionEvent.ACTION_MOVE: {
            if (mIsScrolling) {
                // We're currently scrolling, so yes, intercept the 
                // touch event!
                return true;
            }

            // If the user has dragged her finger horizontally more than 
            // the touch slop, start the scroll

            // left as an exercise for the reader
            final int xDiff = calculateDistanceX(ev); 

            // Touch slop should be calculated using ViewConfiguration 
            // constants.
            if (xDiff > mTouchSlop) { 
                // Start scrolling!
                mIsScrolling = true;
                return true;
            }
            break;
        }
        ...
    }

    // In general, we don't want to intercept touch events. They should be 
    // handled by the child view.
    return false;
}
Run Code Online (Sandbox Code Playgroud)

编辑:回答评论.
这是来自同一链接的一些代码,显示如何在元素周围创建矩形的参数:
4b.

// The hit rectangle for the ImageButton
myButton.getHitRect(delegateArea);

// Extend the touch area of the ImageButton beyond its bounds
// on the right and bottom.
delegateArea.right += 100;
delegateArea.bottom += 100;

// Instantiate a TouchDelegate.
// "delegateArea" is the bounds in local coordinates of 
// the containing view to be mapped to the delegate view.
// "myButton" is the child view that should receive motion
// events.
TouchDelegate touchDelegate = new TouchDelegate(delegateArea, myButton);

// Sets the TouchDelegate on the parent view, such that touches 
// within the touch delegate bounds are routed to the child.
if (View.class.isInstance(myButton.getParent())) {
    ((View) myButton.getParent()).setTouchDelegate(touchDelegate);
}
Run Code Online (Sandbox Code Playgroud)