Android ViewPager嵌套,ListView中的列表项实现水平滑动

12

我在一个活动的根级别上有一个 ViewPager。

每个页面都包含一个 ListFragment(由 FragmentPagerAdapter 支持)。

某些列表视图项应该包含另外的 ViewPager,以支持滑动那些项的内容(例如,在列表项内部的水平画廊)。

如何嵌套视图翻页器?ViewPager -> ListView(在一个页面中)-> ViewPager(在列表项内部)

我可以在水平方向上在 ListFragments 之间滑动,也可以在垂直方向上滑动整个列表,但是无法在列表项中进行滑动。

3个回答

11

我向内部的ViewPager添加了一个OnTouchListener

private OnTouchListener mSuppressInterceptListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(
                event.getAction() == MotionEvent.ACTION_DOWN &&
                v instanceof ViewGroup
        ) {
                ((ViewGroup) v).requestDisallowInterceptTouchEvent(true);
        }
        return false;
    }
};

这只是在内部 ViewPager 上检测 ACTION_DOWN 触摸事件,并防止外部的触摸拦截。因为它返回 false,所以只有 ACTION_DOWN 事件会被触发;所有其他事件都将被忽略。您可以将此侦听器添加到每个要“保护”免受外部 ViewPager 滚动影响的元素上,但显然,如果您想在这些元素上捕获任何其他触摸行为,则需要在触摸侦听器内部处理它们并可能实现更好的侦听器。

感谢 @Rodja 首先给了我这个想法。


2
哇,整洁多了。谢谢! - Rodja
迄今为止最简单的解决方案。 - OcuS
1
真不敢相信它的运行如此顺利。非常感谢,Andrew 和 Rodja! - Aman Alam
我遇到了类似的问题,这使我能够左右滑动。如果我还想启用点击功能,然后打开所选视图怎么办? - Eric
你可以通过监听 ACTION_DOWN 和 ACTION_UP 事件来编写自己的点击监听器;如果它们之间所有 ACTION_MOVE 事件的总和小于系统的触摸阈值(见下文),则将其视为单击。http://developer.android.com/reference/android/view/ViewConfiguration.html 中提供了触摸阈值、长按等常量,基本上满足你的需求。 - Andrew Wyld
我对此有一个后续问题... 如果我们禁用父ViewPager上的分页(通过调用setPagingEnabled(false)),并使用PagerTabStrip在其中导航,子/嵌套ViewPager是否仍然会接收触摸事件? - Vaibhav Singhal

3

虽然这不是最好的交互设计,但是可以通过覆盖根级Activity的dispatchTouchEvent(MotionEvent ev)方法,并在mainPager和当前ListView上使用requestDisallowInterceptTouchEvent(true)来防止其他滚动来实现。看看这个例子:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {

    Fragment listFragment = getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + R.id.pager + ":" + (mainPager.getCurrentItem()));
    mainPager.getChildAt(mainPager.getCurrentItem());
    if (listFragment == null)
        return super.dispatchTouchEvent(ev);
    ViewPager embeddedPager = (ViewPager) listFragment.getView().findViewById(R.id.videopager);
    if (embeddedPager != null) {
        int[] position = new int[2];
        embeddedPager.getLocationOnScreen(position);
        if (ev.getY() > position[1] && ev.getY() < position[1] + embeddedPager.getHeight()) {
            mainPager.requestDisallowInterceptTouchEvent(true);
            if (embeddedPager.getScrollX() % embeddedPager.getWidth() != 0) {
                ListView listView = (ListView) listFragment.getView().findViewById(
                        android.R.id.list);
                listView.requestDisallowInterceptTouchEvent(true);
            }
        }
    }

    return super.dispatchTouchEvent(ev);
}

谢谢这个建议,我稍微修改了一下,让您可以在Activity#dispatchTouchEvent(MotionEvent) 方法以外的其他位置放置代码,但是我使用的基本上是您的想法 :) - Andrew Wyld

0

你不能真正嵌套需要相同手势控制的元素。由于视图翻页器已经捕获了水平运动,你的嵌套元素将无法获取它。你可能可以通过管理焦点等方式来解决这个问题,但最终你的应用程序将会让用户感到困惑。最好不要嵌套使用相同交互的元素...在这种情况下,就是两个视图翻页器都监视侧向运动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接