将ScrollView中的触摸事件委托给垂直ViewPager

时间:2018-03-12 15:24:05

标签: android android-viewpager kotlin android-scrollview

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

的内容
<MyScrollView>
    <LinearLayout orientation=vertical>
        ...
        ...
    </LinearLayout>
</MyScrollView>

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

我试验了一大堆拦截ScrollView中的触摸事件以某种方式将MotionEvent发送到VerticalViewPager而没有任何好运。

这显然不起作用,但为了让谈话继续进行,我目前在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)
}

这种行为不稳定,不值得信任,根本不是。非常感谢任何输入!

2 个答案:

答案 0 :(得分:0)

这里的解决方案可能非常类似于此: (原始答案是针对webview,但逻辑是相同的)

Scroll webview horizontally inside a ViewPager

答案 1 :(得分:0)

我认为让ViewPager启动时让ScrollView指示的想法非常好,它已经使用requestDisallowInterceptTouchEvent来阻止ViewPager拦截滚动。您需要的是使用相同的方法允许在您指示的情况下截取,即ScrollView到达顶部或底部时。

因此,如果ScrollView处理了ACTION_MOVE触摸事件,但得到的滚动偏移没有改变,我们可以假设我们已经滚过顶部或底部(现在已经过度滚动)。可能有更好的方法来检测过度滚动,因此请以此为出发点进行实验:

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

编辑 - 我快速玩了一下,认为这很好用

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 - 如果有任何滚动,这将保留触摸的所有权,因此切换页面需要单独触摸

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