滚动型的儿童观,如何有条件地拦截滚动有条件、儿童

2023-09-05 10:47:33 作者:情兽i

我有一个容器的ViewGroup ,让我们把它叫做屏幕在滚动型。这种容器视图举办一些其他的浏览我们姑且称之为控件,其中一些有兴趣的$ P $从滚动pventing的滚动型和使用MotionEvent过问(例如pannable图像)

I have a container ViewGroup, lets call it screen inside a ScrollView. This container view hosts a number of other Views let's call them widgets, and some of them are interested in preventing the ScrollView from scrolling and using the MotionEvent theirselves (for example a pannable image)

我想不出合适的情况下拦截策略来使用。 滚动型总是处理事件前的孩子,或者孩子们处理该事件,但滚动视图是禁用的。

I can't figure out the proper event intercept strategy to use. ScrollView always processes the event before the children, or the children process the event but scrollview is disabled.

我读到发布的getParent()。requestDisableInterceptTouchEvent()在孩子的意见,如果这个观点要捕获事件,但他们的的onTouchEvent 不叫,我想是因为滚动型已提前席卷了事件。我想的是,我有2个水平层(容器+部件)prevents这从工作,我想容器的ViewGroup 已经在这里发挥重要的作用,但我不能找出哪一个?

I read about issuing getParent().requestDisableInterceptTouchEvent() in the child views if this view wants to capture the event, but their onTouchEvent is not called, I suppose because ScrollView has engulfed the event beforehand. I guess the fact that I have 2 levels of layers (container + widgets) prevents this from working, I suppose the container ViewGroup has to play an important part here, but I can't figure out which one...

我可以知道,在滚动型的 onInterceptTouchEvent 的水平,这插件的容器 ViewGroup中已经触碰来决定,如果我要截取或不?

Can I know, at the ScrollView's onInterceptTouchEvent level, which widget on the container viewGroup has been touched to decide if I should intercept or not?

如何才能使小部件层的的的ViewGroup 之前滚动型这样我就可以叫的getParent()。onRequestDisableInterceptTouch() ...或者是的getParent()的getParent()。onRequestDisableInterceptTouch()

How can the 'widget' layers in the ViewGroup get the event before ScrollView so I can call getParent().onRequestDisableInterceptTouch() ... or is it getParent().getParent().onRequestDisableInterceptTouch()?

在此先感谢

我看过相关的问题,但没有运气... 在处理触摸事件滚动型的Andr​​oid

I've read related questions but no luck ... Handle touch events in ScrollView Android

推荐答案

可口可乐和放大器经过一夜好;调试我设法得到这个工作。我同意的解决方案,以防万一有兴趣的人,因为我花了相当多的时间来运行它。

Well after a night of coca cola & debugging I managed to get this to work. I share the solution just in case it is of interest to anyone, because it took me quite a lot of time to get it running.

我没把它与的getParent()运行。onRequestDisableInterceptTouch(),我很接近,但无法找到一种方法为孩子小部件得到他们所需要的滚动一次MotionEvents我拦截父的触摸,所以尽管外周涡旋是prevented正确,内部部件不滚动。

I didn't manage to get it running with getParent().onRequestDisableInterceptTouch(), I was close, but couldn't find a way for the child widgets to get the MotionEvents they need for scrolling once I intercepted the touch on the parent, so even though the outer scroll was prevented correctly, the inner widgets didn't scroll.

所以,解决的办法就是 interceptTouchEvents 在孩子只有,然后如果孩子是滚动(称为属性),和触摸是ACTION_DOWN ,然后禁用滚动型两级以上。如果触摸是ACTION_UP,我们启用了滚动视图。

So the solution is to interceptTouchEvents in the children ONLY, and if the children is scrollable (known property), and the touch is ACTION_DOWN, then disable the scrollview two levels above. If the touch is ACTION_UP, we enable the scrollview.

要启用/禁用滚动视图我刚拦截触摸事件,并与一个标志筛选事件或不

To enable/disable the scrollview I just intercept the touch event and with a flag filter the event or not.

我做了三个辅助类,一个是滚动型,一为容器,一个用于小部件:

I did three auxiliary classes, one for the ScrollView, one for the Container, One for the widgets:

本类包装每一个部件,如果我叫setNeedsScroll(真),那么倒是会被拦截,当它被触摸,它会(告诉容器)告诉滚动视图禁用本身。当触摸被释放时,它将重新启用滚动视图。

This class wraps every widget and, if I call setNeedsScroll(true) , then touches will be intercepted, and when it is touched, it will (tell the container to) tell the scrollview to disable itself. When the touch is released, it will re-enable the 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);
    }
}

这是容器,独生子女滚动视图,并拥有不同的小部件。它只是提供了对孩子的方法,使他们能启用/禁用滚动:

This is the container, only child of the scrollview, and holds the different widgets. It just provides methods for the children so they can enable/disable the scroll:

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

和最后一个滚动视图能够失活。它禁用滚动老斯库尔,拦截和阻断事件。

and finally a scrollview capable of deactivation. It disables the scroll 'old-skool', intercepting and blocking events.

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