将触摸事件从ScrollView委派给垂直ViewPager [英] Delegate touch event from ScrollView to vertical ViewPager

查看:78
本文介绍了将触摸事件从ScrollView委派给垂直ViewPager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个VerticalViewPager,其中每个子片段都包含类似

I have a VerticalViewPager where each child fragment contain something like

<MyScrollView>
    <LinearLayout orientation=vertical>
        ...
        ...
    </LinearLayout>
</MyScrollView>

MyScrollView滚动到底部时,我希望VerticalViewPager插入并发挥其魔力.同样,如果将MyScrollView滚动到最顶部.

When MyScrollView is scrolled to the bottom, I'd like the VerticalViewPager to kick in and do its magic. Likewise if I scroll the MyScrollView to the very top.

我已经尝试了一些拦截ScrollView中的触摸事件的方法,以便以某种方式将MotionEvent分发给VerticalViewPager,而没有任何好运.

I've experimented a bunch with intercepting the touch events in the ScrollView to somehow dispatch the MotionEvent to the VerticalViewPager without any good luck.

这显然是行不通的,但是为了进行对话,我目前正在MyScrollView

This obviously doesn't work, but to get the conversation going I currently do something like the following in MyScrollView

override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
    return super.onInterceptTouchEvent(ev) && atBottom
}

override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
    atBottom = getChildAt(0).bottom <= (height + scrollY)
    super.onScrollChanged(l, t, oldl, oldt)
}

这工作不稳定且不可信,根本不行.任何输入,我们将不胜感激!

This works shaky and untrustworthy and not really at all. Any input is greatly appreciated!

推荐答案

我认为您的想法是让ScrollView决定何时应启动ViewPager,它已经在使用requestDisallowInterceptTouchEvent来防止ViewPager拦截滚动. .您需要的是在您指定的情况下(即ScrollView到达顶部或底部时)使用相同的方法 进行拦截.

I think your idea to have the ScrollView dictate when the ViewPager should kick in is pretty good, it's already using requestDisallowInterceptTouchEvent to prevent the ViewPager from intercepting the scroll. What you need is use this same method to allow the intercept in the circumstances you've indicated, which is when the ScrollView has reached the top or bottom.

因此,如果ScrollView处理ACTION_MOVE触摸事件,但滚动的偏移量没有改变,我们可以假定我们已经滚动到顶部或底部(现在正在过度滚动).也许有更好的方法来检测过度滚动,因此可以以此为起点进行实验:

So if the ScrollView handles an ACTION_MOVE touch event but the resulting scroll offset hasn't changed we can assume that we've scrolled past the top or bottom (and are now overscrolling). There may be a better way to detect overscroll so have an experiment with this as a starting point:

//MyScrollView.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    boolean handled = super.onTouchEvent(ev);
    if (handled && ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
        int y = getScrollY();
        boolean moved = y != prevY;
        prevY = y;
        // This is the important part to allow the parent to intercept
        if (!moved) {
            ViewParent parent = getParent();
            if (parent != null) {
                parent.requestDisallowInterceptTouchEvent(false);
            }
        }
        // Also important to re
        return moved;
    }
    return handled;
}

编辑-我快速浏览了一下,并认为效果很好

EDIT - I had a quick play around and think this works nicely

public class MyScrollView extends ScrollView {

    private boolean clampedY;

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

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean handled = super.onTouchEvent(ev);
        if (handled) {
            ViewParent parent = getParent();
            switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_MOVE:
                    if (clampedY && parent != null) {
                        parent.requestDisallowInterceptTouchEvent(false);
                    }
                    break;
                case MotionEvent.ACTION_DOWN:
                    clampedY = false;
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                    break;
            }
        }
        return handled;
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        this.clampedY = clampedY;
    }
}

编辑2-如果有任何滚动,则将保留触摸的所有权,因此需要单独的触摸来切换页面

EDIT 2 - This will keep ownership of the touch if there has been any scroll, so a separate touch is required to switch page

public class MyScrollView extends ScrollView {

    private boolean scrolled;

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

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean handled = super.onTouchEvent(ev);
        if (handled) {
            ViewParent parent = getParent();
            switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_MOVE:
                    if (!scrolled && parent != null) {
                        parent.requestDisallowInterceptTouchEvent(false);
                    }
                    break;
                case MotionEvent.ACTION_DOWN:
                    scrolled = false;
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                    break;
            }
        }
        return handled;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (t != oldt) {
            scrolled = true;
        }
    }
}

这篇关于将触摸事件从ScrollView委派给垂直ViewPager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆