Infinite ViewPager
Asked Answered
I

2

19

This seems possible, but I'm having a little trouble figuring out how to implement a ViewPager that can page indefinitely.

My use case is for a calendar that shows a month at a time, but would be able to switch to any month by paging enough times.

Currently I'm just extending PagerAdapter, and 3 custom MonthViews are added like so:

    @Override
    public Object instantiateItem(View collection, int position) {
        final MonthView mv = new MonthView(HistoryMonthActivity.this);
        mv.setLayoutParams(new ViewSwitcher.LayoutParams(
                android.view.ViewGroup.LayoutParams.MATCH_PARENT,
                android.view.ViewGroup.LayoutParams.MATCH_PARENT));
        mv.setSelectedTime(mTime);

        ((DirectionalViewPager) collection).addView(mv, 0);

        return mv;
    }

I would like to keep only 3 MonthViews in memory at a time, so that there isn't a huge delay in displaying data from my database on each MonthView when the user is tabbing. So every time a new page is shown, I will need to remove one MonthView and add one MonthView. If anyone has a better idea for the same functionality , I'd love to hear it!

I'm thinking of trying to use a FragmentStatePagerAdapter.

Inmesh answered 16/9, 2011 at 4:1 Comment(0)
I
8

I was able to implement this using a little magic in my MonthViews, my PagerAdapter's OnPageChangeListener, as well as with editing the source code of ViewPager itself. If anyone is interested in how I achieved it, check out the source code or comment with a specific question.

Inmesh answered 18/9, 2011 at 17:6 Comment(6)
You worked pretty hard to get that working! You should be able to simplify it by utilising the PagerAdapter method getItemPosition()Paramorphism
Perhaps, but from the documentation, this would require calls to notifyDataSetChanged(), which in my experience are not super efficient and cause noticeable graphical hiccups and screen flashes.Inmesh
@JonWillis notifyDataSetChanged() shouldn't really be causing issues. I'd try again just to makesure.Wheal
Note that I had to add this line for the application not to crash when I needed constant access to all the pages: mViewPager.setOffscreenPageLimit(3);Succinctorium
Can you share the changed you made to the ViewPager?Xylotomy
Nice Piece of Art there !Gummosis
M
6

Actually, I've been looking at the various ways to do this "infinite" pagination, and even though the human notion of time is that it is infinite (even though we have a notion of the beginning and end of time), computers deal in the discrete. There is a minimum and maximum time (that can be adjusted as time goes on, remember the basis of the Y2K scare?).

Anyways, the point of this discussion is that it is/should be sufficient to support a relatively infinite date range through an actually finite date range. A great example of this is the Android framework's CalendarView implementation, and the WeeksAdapter within it. The default minimum date is in 1900 and the default maximum date is in 2100, this should cover 99% of the calendar use of anyone within a 10 year radius around today easily.

What they do in their implementation (focused on weeks) is compute the number of weeks between the minimum and maximum date. This becomes the number of pages in the pager. Remember that the pager doesn't need to maintain all of these pages simultaneously (setOffscreenPageLimit(int)), it just needs to be able to create the page based on the page number (or index/position). In this case the index is the number of weeks that the week is from the minimum date. With this approach you just have to maintain the minimum date and the number of pages (distance to the maximum date), then for any page you can easily compute the week associated with that page. No dancing around the fact that ViewPager doesn't support looping (a.k.a infinite pagination), and trying to force it to behave like it can scroll infinitely.

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

Then WeekDaysFragment can easily display the week starting at the date passed in its arguments.

Mikaelamikal answered 26/12, 2012 at 22:31 Comment(2)
Nice way of thinking out of the box.Silvereye
I know this is an old answer, but just to add more power to this, I just tested Google Calendar app and the max I could go back to is December 1969. I was able to go up to January 2037. So when implementing a calendar, there's no need stress over this, even if you need to go a couple of millenia back.Highpowered

© 2022 - 2024 — McMap. All rights reserved.