Android:拦截从父级到子视图的触摸手势处理

时间:2017-05-12 06:54:25

标签: android ontouchlistener motionevent

所以我有以下视图结构:

  • 的LinearLayout
    • Horizo​​ntalScrollView
    • 其他儿童观点

可点击的父LinearLayout具有自定义选择器(按下时更改颜色)。我希望能够触摸LinearLayout中的Horizo​​ntalScrollView,并且只要它不是滚动动作,它仍然可以处理LinearLayout中的触摸。如果我进行滚动动作,则Horizo​​ntalScrollView应截取手势并取消LinearLayout的触摸。基本上,我希望能够从子视图中截取手势,而不是作为标准的父级。

我尝试通过创建执行以下操作的扩展类来手动处理MotionEvent:

的LinearLayout

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);
}

Horizo​​ntalScrollView

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);
}

这几乎奏效了。当我触摸Horizo​​ntalScrollView时,LinearLayout显示按下的状态UI并在点击完成时激活。如果我触摸并滚动Horizo​​ntalScrollView然后滚动工作。当我放开滚动时,LinearLayout的点击处理程序不会因为被截获而触发。但问题是,在我开始滚动之前,LinearLayout更改为按下状态,即使手势完成后也不会重置。在我尝试手动取消LinearLayout手势的额外尝试中,我一直遇到其他问题。此外,LinearyLayout中还有其他按钮,单击它们时不应允许父LinearLayout显示按下状态。有什么建议?是否存在拦截儿童触摸事件的固定模式?我确信两个班级都能相互了解,但我试图避免将它们联系起来。

1 个答案:

答案 0 :(得分:0)

以下为所有案件的工作:

<强> 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;
}