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

我有一个容器ViewGroup,让我们在ScrollView中调用它.这个容器视图包含许多其他视图,让我们称它们为小部件,其中一些有兴趣阻止ScrollView滚动并使用MotionEvent自己(例如一个pannable图像)

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

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

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

要么…

ViewGroup中的’widget’层如何在ScrollView之前获取事件,因此我可以调用getParent().onRequestDisableInterceptTouch()…或者是getParent().getParent().onRequestDisableInterceptTouch()?

提前致谢

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

解决方法

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

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

所以解决方法是仅在子节点中拦截触发事件,如果子节点是可滚动的(已知属性),并且触摸是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);
    }
}

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

相关文章

Android 如何解决dialog弹出时无法捕捉Activity的back事件 在...
Android实现自定义带文字和图片的Button 在Android开发中经常...
Android 关于长按back键退出应用程序的实现最近在做一个Andr...
android自带的时间选择器只能精确到分,但是对于某些应用要求...