我决定将这个问题发布回答to this comment回答这个问题:
How to handle click in the child Views, and touch in the parent ViewGroups?
我会在此处粘贴评论:
假设我想覆盖触摸事件仅用于处理某些事件 孩子们,我可以在这个功能中做些什么让它起作用? 我的意思是,对于一些孩子来说,它会照常工作,而对于一些孩子来说 父母视图将决定他们是否会获得触摸事件。
所以问题是:如何阻止父onTouchEvent()
覆盖某些子元素onTouchEvent()
,同时覆盖其他子元素?
答案 0 :(得分:28)
onTouchEvents()
可由boolean
onInterceptTouchEvent管理。 OnInterceptTouchEvent
的默认值为false。
在孩子面前收到父母的onTouchEvent
。如果OnInterceptTouchEvent
返回false,它会将链中的运动事件发送到子项的OnTouchEvent
处理程序。如果它返回true,则父级将处理触摸事件。
然而,可能存在这样的情况:我们希望一些子元素管理OnTouchEvent
,一些子元素由父视图(或可能是父视图的父元素)管理。
这可以通过多种方式进行管理。
OnInterceptTouchEvent
影响的一种方式。public void requestDisallowInterceptTouchEvent(boolean disallowIntercept)
如果元素启用了事件处理程序,这可以防止任何父视图管理此元素的OnTouchEvent
。
OnInterceptTouchEvent
为false,则会评估子元素OnTouchEvent
。如果处理各种触摸事件的子元素中有方法,则禁用的任何相关事件处理程序都会将OnTouchEvent返回给父元素。 这个回答:
https://stackoverflow.com/a/13540006/3956566可以很好地显示触摸事件的传播如何通过:
parent -> child|parent -> child|parent -> child views.
OnInterceptTouchEvent
返回不同的值。此示例取自Managing Touch Events in a 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;
}
编辑:回答评论
这是来自同一链接的一些代码,显示如何在元素周围创建矩形的参数:
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);
}
答案 1 :(得分:1)
让我们重新解决这个问题。
你碰巧有一群带有一堆孩子的ViewGroup。您希望拦截触摸事件以获取具有此ViewGroup的所有内容,但有一些孩子的例外情况。
我一直在寻找同一个问题的答案。没有找到任何合理的东西,因此我自己提出以下解决方案。
以下代码段概述了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;
}