简体   繁体   English

如何查找MotionEvent ACTION_CANCEL的源视图

[英]How to find the source view of a MotionEvent ACTION_CANCEL

How can I find the view causing a MotionEvent ACTION_CANCEL? 如何找到导致MotionEvent ACTION_CANCEL的视图? I have a view "A" which is receiving ACTION_CANCEL and I don't want that to happen. 我有一个接收ACTION_CANCEL的视图“A”,我不希望这种情况发生。 Somewhere, a view "B" is "consuming" the MotionEvent. 在某处,视图“B”正在“消耗”MotionEvent。 I'm hoping there is a way to find out who is "B" so I can address this misfunctionality. 我希望有办法找出谁是“B”,这样我才能解决这个错误的问题。

I've tried looking through my code for various OnTouchEvent() and OnInterceptTouchEvent() handlers but haven't yet found a culprit. 我已经尝试查看我的代码中的各种OnTouchEvent()和OnInterceptTouchEvent()处理程序,但还没有找到罪魁祸首。

I've also put a break point at the problematic ACTION_CANCEL but am not able to recognize anything in the MotionEvent that might represent "B". 我还在有问题的ACTION_CANCEL上设置了一个断点但是我无法识别可能代表“B”的MotionEvent中的任何内容。

If a parent is intercepting the motion event, the only way to prevent this is to prevent the parent from intercepting that event. 如果父母正在拦截运动事件,防止这种情况的唯一方法是阻止父母拦截该事件。 This can be managed well in two ways. 这可以通过两种方式很好地管理。

Without seeing specific code and wanting a generalised solution I would suggest the following. 如果没有看到具体的代码并想要一个通用的解决方案,我建议如下。

I would suggest managing your touch events for the parents and the child by managing the 我建议通过管理家长和孩子来管理你的触摸事件
requestDisallowInterceptTouchEvent(boolean) and requestDisallowInterceptTouchEvent(boolean)

onInterceptTouchEvent(android.view.MotionEvent) event handlers of every view/viewgroup within the affected views A, B C. 受影响的视图A,B中的每个视图/视图组的onInterceptTouchEvent(android.view.MotionEvent)事件处理程序。

By disallowing parent intercepts in the child, this assists you in catching parent intercepts you haven't accounted for, and also to customise and vary the child elements from within one parent. 通过禁止孩子中的父级拦截,这有助于您捕捉未考虑的父级拦截,并且还可以在一个父级内定制和更改子元素。

This must be managed from your highest parent of your view/viewGroup and managed through all parent and child relationships. 这必须从您的view / viewGroup的最高父级进行管理,并通过所有父级和子级关系进行管理。

Checking for listviews, any element that has a inbuilt touch events. 检查列表视图,具有内置触摸事件的任何元素。

android.com/training/gestures/viewgroup android.com/training/gestures/viewgroup

In terms of finding the offending view that is intercepting the event, that cannot be answered except by the logic of: 在找到拦截事件的违规视图方面,除了以下逻辑之外无法回答:

Go through each parent to child/parent to child view. 遍历每个父级到子级/父级到子级视图。 Methodically check the ontouch handling within each view/view group as shown in my diagram. 有条不紊地检查每个视图/视图组中的ontouch处理,如图中所示。

查看图表

There is some more detail in these answers here: 这些答案中有更多细节:
https://stackoverflow.com/a/30966413/3956566 https://stackoverflow.com/a/30966413/3956566
https://stackoverflow.com/a/6384443/3956566 https://stackoverflow.com/a/6384443/3956566

I'm sure you understand this, but to me, it's the simplest solution. 我相信你明白这一点,但对我来说,这是最简单的解决方案。

Beyond this, we'd need to look at your code to troubleshoot it. 除此之外,我们还需要查看您的代码以对其进行故障排除。

If I got your question correct, you are receiving ACTION_CANCEL probably in the parent and you need to find that view. 如果我的问题正确,您可能在父级中接收ACTION_CANCEL ,您需要找到该视图。 Given event X and Y, you can find view that contains these coordinates at the first moment ACTION_CANCEL occurred. 给定事件X和Y,您可以在ACTION_CANCEL发生的第一时间找到包含这些坐标的视图。 Try calling this method either with top parent (android.R.id.content) or the ViewGroup you are dealing with. 尝试使用顶级父级(android.R.id.content)或您正在处理的ViewGroup调用此方法。

private View findViewAt(View contentView, int eventX, int eventY) {
            ArrayList<View> unvisited = new ArrayList<View>();
            unvisited.add(contentView);
            while (!unvisited.isEmpty()) {
                View child = unvisited.remove(0);
                if(isViewContains(child, eventX, eventY) {
                    Log.i(TAG, "view found! ");
                    unvisited.clear();
                    return child;
                }
                if (!(child instanceof ViewGroup)){
                    continue;
                }
                ViewGroup group = (ViewGroup) child;
                final int childCount = group.getChildCount();
                for (int i=0; i< childCount; i++){
                    unvisited.add(group.getChildAt(i));
                }
            }
      return null;
    }


private boolean isViewContains(View view, int eventX, int eventY) {
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    int x = location[0];
    int y = location[1];
    int width = view.getWidth();
    int height = view.getHeight();
    return eventX < x || eventX > x + width || eventY < y || eventY > y + height;
}

根据我的经验,一个使A视图收到ACTION_CANCEL事件的案例是在用户触摸A之后他们将手指拖出A区域,如果你遇到这种情况,添加一个方法来检查dispatchTouchEvent()上的位置可以救命。

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

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