双向无限/动态ViewPager

17

我从未看到过很好地实现ViewPager的用例。

ViewPager是一个相对静态的结构。向右侧添加页面(将其附加到模型并显示)并不难,但是,应该有一个易于使用的解决方案来扩展PagerAdapter(或其某些子类),使其可以向两个方向扩展。

我可以想象适配器的界面如下:

boolean isEmpty()
boolean hasNext()
boolean hasPrevious()
Object  getNext()
Object  getPrevious()
Object  getItem(int position)

// or if using generics
T       getNext()
T       getPrevious()
T       getItem(int position)

类似于集合迭代器,但是可以双向移动。索引/位置不仅限于0,而是可以使用整个整数类型的范围。也许不要基于数组实现(数组从0到无穷大)。我找到了这个“hack”:dynamically add and remove view to viewpager,但是正如我之前所说,我正在尝试让它自然地工作,而不是维护3、5等项目,并强制ViewPager根据某些扭曲的逻辑更改当前位置。目前是否有足够的实现或者需要实现它?如果需要全新的实现,我愿意提供悬赏以获得答案。

我们可以在ViewPager中添加任意数量的视图。我已经在我的一个应用程序中实现了相同的功能。请查看@FoamyGuy的ViewPager简单演示,其中我们可以拥有无限数量的页面 https://github.com/FoamyGuy/MathFactCards - Pragnani
@Pragnani 但是你只是朝着右方向进行扩展,我正在尝试动态地在两个方向上进行扩展,而不使用任何技巧。 - Marek Sebera
@MarekSebera 最近找到了它... - Pragnani
我想知道Google日历是如何实现的?它感觉像一个无限的视图翻页器,因为你可以不断向左和向右滚动浏览每一天。 - Aleks G
@MichałZ。那就是我试图避免的,因为那是肮脏的黑客行为。 - Marek Sebera
显示剩余5条评论
2个回答

10

这样会有帮助吗,

public static class MyAdapter extends FragmentPagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    @Override
    public Fragment getItem(int position) {
        return getFragmentBasedOnPosition(position);
    }

    private Fragment getFragmentBasedOnPosition(int position) {
        int fragmentPos = position % 3; // Assuming you have 3 fragments
        switch(fragmentPos) {
            case 1:
            return Fragment1.newInstance();
            case 2:
            return Fragment2.newInstance();
            case 3:
            return Fragment3.newInstance();
        }
    }
}

接着,

mPager.setCurrentItem((int)(Integer.MAX_VALUE/2)); // 假设mPager是你的ViewPager


1
这会在某种程度上有所帮助,谢谢,但是对我来说仍然感觉像是奇怪的解决方案。 - Marek Sebera
4
如果使用FragmentStatePagerAdapter,它需要计算每个碎片,这样就会导致内存溢出,因此无法正常工作。 - Hrk

2

使用负数位置值远离ViewPager的自然顺序,这与适配器无关。请查看Android SDK中支持包源代码中ViewPager的源代码。例如,这是一个setCurrentItemInternal私有实现:

void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
    if (mAdapter == null || mAdapter.getCount() <= 0) {
        setScrollingCacheEnabled(false);
        return;
    }
    if (!always && mCurItem == item && mItems.size() != 0) {
        setScrollingCacheEnabled(false);
        return;
    }

    if (item < 0) {
        item = 0;
    } else if (item >= mAdapter.getCount()) {
        item = mAdapter.getCount() - 1;
    }
    final int pageLimit = mOffscreenPageLimit;
    if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
        // We are doing a jump by more than one page.  To avoid
        // glitches, we want to keep all current pages in the view
        // until the scroll ends.
        for (int i=0; i<mItems.size(); i++) {
            mItems.get(i).scrolling = true;
        }
    }
    final boolean dispatchSelected = mCurItem != item;
    populate(item);
    scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}

正如你所看到的,ViewPager明确假定没有负位置值。


那结论是什么?我不想使用负索引。我需要根据自己的自定义模型无限地从两个方向遍历集合。我直接说,解决方案可能不应该基于数组,因为我们将不得不处理负索引。 - Marek Sebera
你写道:“索引/位置不受0以下的限制,而是可以使用整个整数类型的范围。” 你想在哪里使用这些索引?如果在获取/设置当前页面或onChange处理程序中使用,那么上述问题就会出现。如果负索引对ViewPager不可见,那么拥有这样一个索引的意义是什么?请详细说明一下... - alexei burmistrov
我在谈论可能元素的范围,在接口轮廓中我不需要索引,但我需要在两个方向上动态扩展集合。这样调用getPreviousItem就不会停留在Element(0),而是取决于自定义模型中实现的某些其他条件。 - Marek Sebera
所以,如果我理解正确的话,问题可以简化为向普通List添加getModelPosition(item)方法,并通过扩展List.add方法来更新位置-模型位置映射的代码。我说得对吗? - alexei burmistrov
1
你可以使其在两个方向上成为循环,并产生一种无限页面的效果。同时,在下一个或上一个循环插槽中更改视图分页器的内容,例如,前5页的内容将是某些内容, 接下来的5页内容会发生变化, 最后5页的内容从历史记录中获取变化,您必须为每个插槽(5页)维护一个历史记录。 - kaushal trivedi
显示剩余2条评论

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