简体   繁体   English

如何在子视图组和父视图组触摸事件之间变化

[英]How to vary between child and parent view group touch events

I decided to post this question and answer in response to this comment to this question:我决定发布这个问题并回答这个问题的评论
How to handle click in the child Views, and touch in the parent ViewGroups? 如何处理子视图中的点击,以及父视图组中的触摸?

I will paste the comment here:我将在此处粘贴评论:

Suppose I want to override the touch events only for handling some of the children, what can I do inside this function to have it working ?假设我只想覆盖触摸事件来处理一些孩子,我可以在这个函数中做什么才能让它工作? I mean, for some children it would work as usual, and for some, the parent-view will decide if they will get the touch events or not.我的意思是,对于一些孩子来说,它会像往常一样工作,而对于一些孩子来说,父视图将决定他们是否会得到触摸事件。

So the question is this: How do I prevent the parent onTouchEvent() from overriding some child elements' onTouchEvent() , while having it override those of other children?所以问题是:如何防止父onTouchEvent()覆盖某些子元素的onTouchEvent() ,同时让它覆盖其他子元素的那些?

  1. The onTouchEvents() for nested view groups can be managed by the boolean onInterceptTouchEvent .嵌套视图组的onTouchEvents()可以由boolean onInterceptTouchEvent管理。

The default value for the OnInterceptTouchEvent is false. OnInterceptTouchEvent的默认值为 false。

The parent's onTouchEvent is received before the child's.在孩子之前收到父母的onTouchEvent If the OnInterceptTouchEvent returns false, it sends the motion event down the chain to the child's OnTouchEvent handler.如果OnInterceptTouchEvent返回 false,它会将运动事件沿链向下发送到孩子的OnTouchEvent处理程序。 If it returns true the parent's will handle the touch event.如果它返回 true,则父级将处理触摸事件。

However there may be instances when we want some child elements to manage OnTouchEvent s and some to be managed by the parent view (or possibly the parent of the parent).然而,有时我们希望一些子元素管理OnTouchEvent而一些子元素由父视图(或可能是父视图的父视图)管理。

This can be managed in more than one way.这可以通过多种方式进行管理。

  1. One way a child element can be protected from the parent's OnInterceptTouchEvent is by implementing the requestDisallowInterceptTouchEvent .保护子元素免受父元素OnInterceptTouchEvent一种方法是实现requestDisallowInterceptTouchEvent

public void requestDisallowInterceptTouchEvent (boolean disallowIntercept) public void requestDisallowInterceptTouchEvent (boolean disallowIntercept)

This prevents any of the parent views from managing the OnTouchEvent for this element, if the element has event handlers enabled.如果元素启用了事件处理程序,这将阻止任何父视图管理此元素的OnTouchEvent

  1. If the OnInterceptTouchEvent is false, the child element's OnTouchEvent will be evaluated.如果OnInterceptTouchEvent为 false,则将评估子元素的OnTouchEvent If you have a methods within the child elements handling the various touch events, any related event handlers that are disabled will return the OnTouchEvent to the parent.如果子元素中有处理各种触摸事件的方法,则禁用的任何相关事件处理程序都会将 OnTouchEvent 返回给父元素。

This answer:这个答案:
https://stackoverflow.com/a/13540006/3956566 gives a good visualisation of how the propagation of touch events passes through: https://stackoverflow.com/a/13540006/3956566很好地展示了触摸事件的传播方式:
parent -> child|parent -> child|parent -> child views.

  1. Another way is returning varying values from the OnInterceptTouchEvent for the parent.另一种方法是从父对象的OnInterceptTouchEvent返回不同的值。

This example taken from Managing Touch Events in a ViewGroup and demonstrates how to intercept the child's OnTouchEvent when the user is scrolling.此示例取自 在 ViewGroup 中管理触摸事件,并演示了如何在用户滚动时拦截孩子的OnTouchEvent

4a. 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;
}

Edit: To answer comments.编辑:回答评论。
This is some code from the same link showing how to create the parameters of the rectangle around your element:这是同一链接中的一些代码,显示了如何在元素周围创建矩形的参数:
4b. 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);
}

Lets revamp the issue.让我们修改这个问题。

You happen to have a ViewGroup with a bunch of children.你碰巧有一个有一群孩子的 ViewGroup。 You want to intercept the touch event for everything withing this ViewGroup with a minor exception of some children.您想拦截此 ViewGroup 中所有内容的触摸事件,但有一些孩子除外。

I have been looking for an answer for the same question for quite a while.很长一段时间以来,我一直在寻找同一个问题的答案。 Did not manage to find anything reasonable and thus came up on my own with the following solution.没有设法找到任何合理的东西,因此我自己提出了以下解决方案。

The following code snippet provides an overview of the ViewGroup's relevant code that intercepts all touches with the exception of the ones coming from views that happen to have a special tag set (You should set it elsewhere in your code).以下代码片段概述了 ViewGroup 的相关代码,该代码拦截所有触摸,但来自恰好具有特殊标记集的视图的除外(您应该在代码中的其他位置设置它)。

private static int NO_INTERCEPTION;

private boolean isWithinBounds(View view, MotionEvent ev) {
    int xPoint = Math.round(ev.getRawX());
    int yPoint = Math.round(ev.getRawY());
    int[] l = new int[2];
    view.getLocationOnScreen(l);
    int x = l[0];
    int y = l[1];
    int w = view.getWidth();
    int h = view.getHeight();
    return !(xPoint < x || xPoint > x + w || yPoint < y || yPoint > y + h);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    for (int i=0; i<floatingMenuItems.getChildCount(); i++){
        View child = floatingMenuItems.getChildAt(i);
        if (child == null || child.getTag(NO_INTERCEPTION) == null) {
            continue;
        }
        if(isWithinBounds(child, ev)){
            return false;
        }
    }
    return true;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM