[英]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()
,同时让它覆盖其他子元素的那些?
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.这可以通过多种方式进行管理。
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
。
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. 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.
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.