Android:拦截从parent到child视图的触摸手势处理
Android: Intercept touch gesture handling from the parent to the child view
所以我有以下视图结构:
- 线性布局
- 水平滚动视图
- 其他 Child 浏览量
可点击的 parent LinearLayout 有一个自定义选择器(按下时改变颜色)。我希望能够触摸 LinearLayout 中的 HorizontalScrollView 并且仍然处理 LinearLayout 中的触摸,只要它不是滚动运动。如果我执行滚动动作,则 HorizontalScrollView 应该拦截手势并取消 LinearLayout 的触摸。基本上,我希望能够从 child 视图截取手势,而不是标准的 parent。
我尝试通过创建执行以下操作的扩展 类 来手动处理 MotionEvent:
线性布局
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
// Handle the motion event even if a child returned true for OnTouchEvent
base.OnTouchEvent(ev);
return base.OnInterceptTouchEvent(ev);
}
HorizontalScrollView
public override bool OnTouchEvent(MotionEvent e)
{
if (e.Action == MotionEventActions.Down)
{
_intialXPos = e.GetX();
}
if (e.Action == MotionEventActions.Move)
{
float xDifference = Math.Abs(e.GetX() - _intialXPos);
if (xDifference > _touchSlop)
{
// Prevent the parent OnInterceptTouchEvent from being called, thus it will no longer be able to handle motion events for this gesture
Parent.RequestDisallowInterceptTouchEvent(true);
}
}
return base.OnTouchEvent(e);
}
这几乎奏效了。当我触摸 HorizontalScrollView 时,LinearLayout 显示按下状态 UI 并在单击完成时激活。如果我触摸并滚动 HorizontalScrollView,则滚动有效。当我放开滚动时,LinearLayout 的点击处理程序不会触发,因为它已被拦截。但问题是,在我开始滚动之前,LinearLayout 更改为按下状态,即使在手势完成后它也不会重置。在我尝试手动取消 LinearLayout 手势的额外尝试中,我将 运行 保留在其他问题中。此外,LinearyLayout 内部还有其他按钮,单击这些按钮时不应让 parent LinearLayout 显示按下状态。有什么建议么?是否有用于拦截来自 child 的触摸事件的固定模式?我敢肯定,如果 类 彼此都知道,那是有可能的,但我正在努力避免将它们结合起来。
以下适用于所有情况的工作:
InterceptableLinearLayout
public override bool DispatchTouchEvent(MotionEvent e)
{
bool dispatched = base.DispatchTouchEvent(e);
// Handle the motion event even if a child returns true in OnTouchEvent
// The MotionEvent may have been canceled by the child view
base.OnTouchEvent(e);
return dispatched;
}
public override bool OnTouchEvent(MotionEvent e)
{
// We are calling OnTouchEvent manually, if OnTouchEvent propagates back to this layout do nothing as it was already handled.
return true;
}
InterceptCapableChildView
public override bool OnTouchEvent(MotionEvent e)
{
bool handledTouch = base.OnTouchEvent(e);
if ([Meets Condition to Intercept Gesture])
{
// If we are inside an interceptable viewgroup, intercept the motionevent by sending the cancel action to the parent
e.Action = MotionEventActions.Cancel;
}
return handledTouch;
}
所以我有以下视图结构:
- 线性布局
- 水平滚动视图
- 其他 Child 浏览量
可点击的 parent LinearLayout 有一个自定义选择器(按下时改变颜色)。我希望能够触摸 LinearLayout 中的 HorizontalScrollView 并且仍然处理 LinearLayout 中的触摸,只要它不是滚动运动。如果我执行滚动动作,则 HorizontalScrollView 应该拦截手势并取消 LinearLayout 的触摸。基本上,我希望能够从 child 视图截取手势,而不是标准的 parent。
我尝试通过创建执行以下操作的扩展 类 来手动处理 MotionEvent:
线性布局
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
// Handle the motion event even if a child returned true for OnTouchEvent
base.OnTouchEvent(ev);
return base.OnInterceptTouchEvent(ev);
}
HorizontalScrollView
public override bool OnTouchEvent(MotionEvent e)
{
if (e.Action == MotionEventActions.Down)
{
_intialXPos = e.GetX();
}
if (e.Action == MotionEventActions.Move)
{
float xDifference = Math.Abs(e.GetX() - _intialXPos);
if (xDifference > _touchSlop)
{
// Prevent the parent OnInterceptTouchEvent from being called, thus it will no longer be able to handle motion events for this gesture
Parent.RequestDisallowInterceptTouchEvent(true);
}
}
return base.OnTouchEvent(e);
}
这几乎奏效了。当我触摸 HorizontalScrollView 时,LinearLayout 显示按下状态 UI 并在单击完成时激活。如果我触摸并滚动 HorizontalScrollView,则滚动有效。当我放开滚动时,LinearLayout 的点击处理程序不会触发,因为它已被拦截。但问题是,在我开始滚动之前,LinearLayout 更改为按下状态,即使在手势完成后它也不会重置。在我尝试手动取消 LinearLayout 手势的额外尝试中,我将 运行 保留在其他问题中。此外,LinearyLayout 内部还有其他按钮,单击这些按钮时不应让 parent LinearLayout 显示按下状态。有什么建议么?是否有用于拦截来自 child 的触摸事件的固定模式?我敢肯定,如果 类 彼此都知道,那是有可能的,但我正在努力避免将它们结合起来。
以下适用于所有情况的工作:
InterceptableLinearLayout
public override bool DispatchTouchEvent(MotionEvent e)
{
bool dispatched = base.DispatchTouchEvent(e);
// Handle the motion event even if a child returns true in OnTouchEvent
// The MotionEvent may have been canceled by the child view
base.OnTouchEvent(e);
return dispatched;
}
public override bool OnTouchEvent(MotionEvent e)
{
// We are calling OnTouchEvent manually, if OnTouchEvent propagates back to this layout do nothing as it was already handled.
return true;
}
InterceptCapableChildView
public override bool OnTouchEvent(MotionEvent e)
{
bool handledTouch = base.OnTouchEvent(e);
if ([Meets Condition to Intercept Gesture])
{
// If we are inside an interceptable viewgroup, intercept the motionevent by sending the cancel action to the parent
e.Action = MotionEventActions.Cancel;
}
return handledTouch;
}