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

时间:2013-12-15 01:24:43

标签: android touch scrollview touch-event

我有一个容器ViewGroup,我们在ScrollView内称之为屏幕。此容器视图托管了许多其他Views让他们称之为小部件,其中一些人有兴趣阻止ScrollView滚动并使用MotionEvent(例如a) pannable image)

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

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

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

...或

'小部件' ViewGroup 中的图层会在ScrollView之前获取该事件,因此我可以致电getParent().onRequestDisableInterceptTouch() ...或者是getParent().getParent().onRequestDisableInterceptTouch()

提前致谢

我已经阅读了相关问题,但没有运气...... Handle touch events in ScrollView Android

2 个答案:

答案 0 :(得分:9)

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

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

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

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

我做了三个辅助类,一个用于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);
    }
}

这是容器,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);
    }
}

最后是一个能够停用的滚动视图。它禁用滚动'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);
    }
}

答案 1 :(得分:-1)

在Activity中实现View.OnTouchListener并将该侦听器添加到ScrollView。然后在onTouchEvent(...)中返回true。在返回之前,请调用您想要处理该事件的孩子的onTouch