更改ViewPager以启用无限页面滚动

the*_*yro 45 android infinite-scroll android-viewpager

Jon Willis发布了如何使用他的代码实现无限滚动.在那里,他说他在Android支持库的ViewPager类中进行了一些更改.已经进行了哪些更改以及如何使用ViewPager更改"重新编译"库?

pet*_*ejl 38

我使用适配器中的一个小黑客非常简单地解决了这个问题.这是我的代码:

public class MyPagerAdapter extends FragmentStatePagerAdapter
{
    public static int LOOPS_COUNT = 1000;
    private ArrayList<Product> mProducts;


    public MyPagerAdapter(FragmentManager manager, ArrayList<Product> products)
    {
        super(manager);
        mProducts = products;
    }


    @Override
    public Fragment getItem(int position)
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            position = position % mProducts.size(); // use modulo for infinite cycling
            return MyFragment.newInstance(mProducts.get(position));
        }
        else
        {
            return MyFragment.newInstance(null);
        }
    }


    @Override
    public int getCount()
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            return mProducts.size()*LOOPS_COUNT; // simulate infinite by big number of products
        }
        else
        {
            return 1;
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

然后,在ViewPager中,我们将当前页面设置为中间:

mAdapter = new MyPagerAdapter(getSupportFragmentManager(), mProducts);
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(mViewPager.getChildCount() * MyPagerAdapter.LOOPS_COUNT / 2, false); // set current item in the adapter to middle
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的简单解决方案,但随着你增加`LOOPS_COUNT`的值,性能似乎会降低.我不得不在100左右 (5认同)
  • 使用ViewPager的重点是为您管理片段.有了这个解决方案,它每次都会创建一个新的片段.所以是的,这个解决方案将对性能产生很大的影响.您应该从FragmentStatePagerAdapter中删除代码并在此处执行模数技巧:`if(mFragments.size()> position){Fragment f = mFragments.get(position); if(f!= null){return f; } (2认同)

the*_*yro 34

感谢谢谢你的回答.

我有点不同地解决了它.

我更改了android支持库的ViewPager类的代码.方法setCurrentItem(int)

用动画更改页面.此方法调用需要索引的内部方法和允许平滑滚动的标志.这个标志是boolean smoothScroll.使用第二个参数扩展此方法boolean smoothScroll为我解决了这个问题.调用此方法setCurrentItem(int index, boolean smoothScroll)允许我无限期地滚动它.

这是一个完整的例子:

请注意只显示中心页面.此外,我是否单独存储页面,让我更轻松地处理它们.

private class Page {
  View page;
  List<..> data;
}
// page for predecessor, current, and successor
Page[] pages = new Page[3];




mDayPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

        @Override
        public void onPageScrollStateChanged(int state) {

            if (state == ViewPager.SCROLL_STATE_IDLE) {

                if (mFocusedPage == 0) {
                    // move some stuff from the 
                                            // center to the right here
                    moveStuff(pages[1], pages[2]);

                    // move stuff from the left to the center 
                    moveStuff(pages[0], pages[1]);
                    // retrieve new stuff and insert it to the left page
                    insertStuff(pages[0]);
                }
                else if (mFocusedPage == 2) {


                    // move stuff from the center to the left page
                    moveStuff(pages[1], pages[0]); 
                    // move stuff from the right to the center page
                    moveStuff(pages[2], pages[1]); 
                    // retrieve stuff and insert it to the right page
                                            insertStuff(pages[2]);
                }

                // go back to the center allowing to scroll indefinitely
                mDayPager.setCurrentItem(1, false);
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

但是,如果没有Jon Willis Code,我自己也不会解决它.

编辑:这是一篇关于此的博文:

  • 我的github项目会很棒 (5认同)

Paw*_*ari 31

通过覆盖现有适配器类中的4个适配器方法,无限视图分页器

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

    @Override
    public CharSequence getPageTitle(int position) {
        String title = mTitleList.get(position % mActualTitleListSize);
        return title;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int virtualPosition = position % mActualTitleListSize;
        return super.instantiateItem(container, virtualPosition);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        int virtualPosition = position % mActualTitleListSize;
        super.destroyItem(container, virtualPosition, object);
    }
Run Code Online (Sandbox Code Playgroud)

  • 设置适配器后,只需添加yourAwesomePager.setCurrentItem(Integer.MAX_VALUE/2); 从中间开始 (2认同)
  • 不幸的是,当与viewCagerItem结合使用MAX_VALUE时,会遇到性能问题,这是由于viewpager的实现,它遍历所有项目.你会得到ANR/UI线程块. (2认同)

She*_*ouk 9

您需要做的就是查看此处的示例

您会发现在第295行中,页面始终设置为1,因此它可以滚动,并且getCount()方法中的页数为3 .

这些是你需要改变的两个主要内容,其余的是你的逻辑,你可以用不同的方式处理它们.

只需创建一个计算您所在页面的真实页面的个人计数器,因为在第295行始终将当前页面设置为1后,位置将不再可用.

ps这个代码不是我的,你在问题中链接的问题中引用了它


Dan*_*son 7

实际上,我一直在寻找各种方法来实现这种"无限"的分页,即使人类的时间概念是无限的(即使我们有一个时间的开始和结束的概念),计算机交易在离散的.有一个最小和最大时间(可以随着时间的推移调整,记住Y2K恐慌的基础?).

无论如何,这个讨论的重点是,通过实际有限的日期范围支持相对无限的日期范围是足够的/应该足够的.一个很好的例子就是Android框架的CalendarView实现,以及它WeeksAdapter内部的实现.默认的最短日期是1900年,默认的最长日期是2100年,这应该涵盖了今天10年半径范围内任何人日历使用的99%.

他们在实施过程中所做的工作(专注于几周)是计算最小和最大日期之间的周数.这将成为寻呼机中的页数.请记住,寻呼机不需要同时维护所有这些页面(setOffscreenPageLimit(int)),它只需要能够根据页码(或索引/位置)创建页面.在这种情况下,索引是一周从最小日期开始的周数.使用这种方法,您只需要保持最小日期和页数(到最大日期的距离),然后对于任何页面,您都可以轻松计算与该页面关联的周.没有围绕ViewPager不支持循环(又称无限分页)的事实跳舞,并试图强迫它表现得像它可以无限滚动.

new FragmentStatePagerAdapter(getFragmentManager()) {
    @Override
    public Fragment getItem(int index) {
        final Bundle arguments = new Bundle(getArguments());
        final Calendar temp_calendar = Calendar.getInstance();
        temp_calendar.setTimeInMillis(_minimum_date.getTimeInMillis());
        temp_calendar.setFirstDayOfWeek(_calendar.getStartOfWeek());
        temp_calendar.add(Calendar.WEEK_OF_YEAR, index);
        // Moves to the first day of this week
        temp_calendar.add(Calendar.DAY_OF_YEAR,
                -UiUtils.modulus(temp_calendar.get(Calendar.DAY_OF_WEEK) - temp_calendar.getFirstDayOfWeek(),
                7));
        arguments.putLong(KEY_DATE, temp_calendar.getTimeInMillis());
        return Fragment.instantiate(getActivity(), WeekDaysFragment.class.getName(), arguments);
    }

    @Override
    public int getCount() {
        return _total_number_of_weeks;
    }
};
Run Code Online (Sandbox Code Playgroud)

然后WeekDaysFragment可以轻松地显示从其参数传递的日期开始的一周.

或者,似乎Android上的某些版本的日历应用程序使用了一个ViewSwitcher(这意味着只有2个页面,您看到的页面和隐藏页面).然后,它根据用户滑动的方式更改过渡动画,并相应地呈现下一个/上一个页面.通过这种方式,您可以获得无限的分页,因为它只是无限地在两个页面之间切换.这需要View在页面中使用a ,这是我采用第一种方法的方式.

一般来说,如果你想要"无限分页",可能是因为你的网页是以某种方式基于日期或时间.如果是这种情况,请考虑使用相对无限的有限时间子集.CalendarView例如,这是如何实现的.或者你可以使用这种ViewSwitcher方法.这两种方法的优点是,无论做什么特别不一样同ViewSwitcherViewPager,并且不需要任何技巧或重新实施强迫他们的行为无限(ViewSwitcher已经被设计为无限美景之间切换,而是ViewPager被设计为在有限的工作,但不一定是常数,一组页面).