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.

Jon Willis
  • 6,839
  • 4
  • 38
  • 51

2 Answers2

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.

Jon Willis
  • 6,839
  • 4
  • 38
  • 51
  • You worked pretty hard to get that working! You should be able to simplify it by utilising the `PagerAdapter` method [`getItemPosition()`](http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html) – ohhorob Dec 28 '11 at 07:29
  • 1
    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. – Jon Willis Dec 28 '11 at 16:02
  • @JonWillis notifyDataSetChanged() shouldn't really be causing issues. I'd try again just to makesure. – StackOverflowed Aug 22 '12 at 01:31
  • 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);` – Oleg Vaskevich Oct 07 '12 at 14:37
  • Can you share the changed you made to the `ViewPager`? – Leandros Nov 11 '12 at 01:52
  • Nice Piece of Art there ! – Salman Khakwani Sep 04 '15 at 19:12
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.

Dandre Allison
  • 5,795
  • 5
  • 39
  • 55
  • 1
    Nice way of thinking out of the box. – aluxian Jan 27 '15 at 12:59
  • 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. – Not Gabriel Mar 01 '16 at 16:56