Fragment 中带有 Horizo​​ntalScrollView 的垂直 ViewPager

Vertical ViewPager with HorizontalScrollView inside Fragment

我有一个 VerticalViewPager,我想水平滚动其 Fragment 内容。垂直分页工作正常,直到水平内容大到可以滚动为止。之后触摸事件不会传递到 ViewPager,因此分页不再有效。

MVCE

这可以通过设置我刚刚发布的 this answer 中给出的简单项目来重现。

fragment_one.xml 文件替换为

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent" >

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" >

        <TextView
            android:id="@+id/textview"
            android:textSize="30sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </HorizontalScrollView>

</RelativeLayout>

并将文本设置为足以水平滚动的任何长度。

我尝试过的事情

为了回答这个问题和其他类似问题,了解 Android 框架如何处理触摸事件非常有帮助。我的 fuller answer on that is here,但我会在下面包含摘要图。

HorizontalScrollView(图中的视图组 B)在 VerticalViewPager(视图组 A)有机会处理之前处理所有触摸事件。所以解决方法是在VerticalViewPager中使用onInterceptTouchEvent()来选择性过滤垂直滚动条。为此,最简单的方法是使用 GestureDetector.SimpleOnGestureListener.onScroll().

以下是您需要对 VerticalViewPager class 进行的相关更改以实现此目的:

public class VerticalViewPager extends ViewPager {

    GestureDetector mDetector;

    private void init() {
        // ...
        mDetector = new GestureDetector(getContext(), new VerticalScrollListener());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        super.onInterceptTouchEvent(flipXY(ev));
        flipXY(ev);

        return mDetector.onTouchEvent(ev);
    }

    class VerticalScrollListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, 
                                float distanceX, float distanceY) {
            return Math.abs(distanceY) > Math.abs(distanceX);
        }
    }
}