带有子视图的ScrollView,如何有条件地拦截滚动

rup*_*pps 6 android touch scrollview touch-event

我有一个容器ViewGroup,可以把它的屏幕ScrollView.这个容器视图托管了许多其他Views的调用它们的小部件,其中一些有兴趣阻止ScrollView滚动并使用MotionEvent自己(例如一个pannable图像)

我无法弄清楚要使用的正确的事件拦截策略.ScrollView始终在子项之前处理事件,或者子项处理事件但是scrollview已禁用.

我读过关于getParent().requestDisableInterceptTouchEvent()在子视图中发出这个视图是否想要捕获事件,但是onTouchEvent没有调用它们,我想是因为ScrollView事先已经吞没了事件.我想我有2级层(容器+小部件)的事实阻止了它的工作,我想容器ViewGroup必须在这里发挥重要作用,但我无法弄清楚哪一个......

我是否可以在ScrollView's onInterceptTouchEvent级别上知道容器上的哪个小部件viewGroup被触摸以决定是否应该拦截?

要么...

如何才能获得事件中的"小部件"图层,ViewGroupScrollView以便我可以调用getParent().onRequestDisableInterceptTouch() ......或者是它getParent().getParent().onRequestDisableInterceptTouch()

提前致谢

我已阅读相关问题,但没有运气...... 在ScrollView Android中处理触摸事件

rup*_*pps 9

经过一夜的可口可乐和调试后,我设法让这个工作.我会分享解决方案以防万一对任何人感兴趣,因为我花了很多时间才能让它运行起来.

我没有设法让它运行getParent().onRequestDisableInterceptTouch(),我很接近,但是当我拦截父母的触摸时,找不到让小部件获取他们滚动所需的MotionEvent的方法,所以即使外部滚动是正确阻止,内部小部件没有滚动.

因此解决方案是interceptTouchEvents 仅在子项中,如果子项是可滚动的(已知属性),并且触摸是ACTION_DOWN,则禁用上面两级的scrollview.如果触摸是ACTION_UP,我们启用scrollview.

要启用/禁用滚动视图,我只是拦截触摸事件,并使用标志过滤事件与否.

我做了三个辅助类,一个用于ScrollView,一个用于容器,一个用于小部件:

这个类包装了每个小部件,如果我调用setNeedsScroll(true),那么将拦截触摸,当它被触摸时,它将(告诉容器)告诉scrollview禁用它自己.触摸释放后,将重新启用滚动视图.

class WidgetWrapperLayout extends FrameLayout {

    private boolean mNeedsScroll=false;

    public WidgetWrapperLayout(Context context) {
        super(context);
    }

  /** Called anytime, ie, during construction, to indicate that this 
    * widget uses vertical scroll, so we need to disable its container scroll 
    */

    public void setNeedsScroll(boolean needsScroll) { 
        mNeedsScroll=needsScroll; 
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mNeedsScroll)  {
            switch (ev.getAction()) {  
            case MotionEvent.ACTION_DOWN:
                ((SlideLayout)getParent()).setEnableScroll(false);
                break;
            case MotionEvent.ACTION_UP:
                ((SlideLayout)getParent()).setEnableScroll(true);
                break;
            }
            return false;
        }
        return super.onInterceptTouchEvent(ev);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是容器,也是唯一的子容器,scrollview并且包含不同的小部件.它只为孩子们提供方法,以便他们可以启用/禁用滚动:

public class ContainerLayout extends FrameLayout {

    public ContainerLayout(Context context) {
        super(context);
    }

    public void setEnableScroll(boolean status) {
        if (Conf.LOG_ON) Log.d(TAG, "Request enable scroll: "+status);
        ((StoppableScrollView)getParent()).setScrollEnabled(status);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是一个能够停用的滚动视图.它禁用滚动'old-skool',拦截和阻止事件.

public class StoppableScrollView extends ScrollView {

    private String TAG="StoppableScrollView";

    private boolean mDisableScrolling=false;

    public StoppableScrollView(Context context) {
        super(context);
    }

    /** Enables or disables ScrollView scroll */
    public void setScrollEnabled (boolean status) { 
        if (Conf.LOG_ON) Log.d(TAG, "Scroll Enabled "+status);
        mDisableScrolling=!status; 
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mDisableScrolling) return false;
        return super.onInterceptTouchEvent(ev);
    }
}
Run Code Online (Sandbox Code Playgroud)