Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a page to the beginning of ViewPager?

About my application
I am developing a calendar application.Want to show monthview with horizontal swipe navigation? Which means an infinite scrolling User can scroll to right and left monthwise to any date/month of any year. I found ViewPager is very use full to achive this.(I don't really know any what are other use full methods).And in by clicking a date cell user is able to see details or events added to that date (I don't want to link with device calendar).

About the issue
I am able to add new page to the end of my View pager without any problem.But If user swipes to left I need add a Page to the beginning of my ViewPager. .when I add a page to the begning ( index position of zero) this will replace my current page on position zero and only able to add a one page (No new pages are added I don't know why ). And after adding the page on zero position I am not able to add even add page to the end of view pager when user swipes to right and reachees the last page Force close occur with an error:

java.lang.IllegalStateException: Can't change tag of fragment MyFragment{40526bb8 #2  id=0x7f070000 android:switcher:2131165184:2}: was android:switcher:2131165184:2 now android:switcher:2131165184:3

In simple sentence
I want to know what's the right way to add pages to the beginning and ending of View pager?

Code

Activity and Adapter

    public class PageViewActivity extends FragmentActivity {

    ViewPager pager;
    MyPageAdapter pageAdapter;
    ArrayList<Fragment> fragments;

    int page_num = 0;
    int current_page = 1;
    int selected_page = 1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_page_view);

        pager = (ViewPager) findViewById(R.id.viewpager);

        fragments = getFragments();

        pageAdapter = new MyPageAdapter(getSupportFragmentManager(), pager,
                fragments);

        pager.setAdapter(pageAdapter);
        pager.setCurrentItem(2);
        pager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int arg0) {

                // setting the selected page index
                selected_page = arg0;       
                //calling add page
                addPage();

            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                // TODO Auto-generated method stub          

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
                // TODO Auto-generated method stub
            }
        });


    }

    public int addPage() {

        System.out.println("Add page called "+selected_page);
        // checking if selected page is second last and if tru adds new page 
        if (selected_page >= (pageAdapter.getCount() - 1)) {    

            System.out.println("on first condition");

            Fragment new_fragment = MyFragment.newInstance("Added to last  "+ (pageAdapter.getCount() + 1));
            //pageAdapter.fragments.add(pageAdapter.getCount(), new_fragment);
            System.out.println("pageAdapter.getCount()   :  "+pageAdapter.getCount());
            pageAdapter.add(pageAdapter.getCount(), new_fragment);
            current_page = selected_page;           
            pageAdapter.notifyDataSetChanged();
            System.out.println("New page added");
        }else if((selected_page-1)<=0){

            System.out.println("on second condition");

            Fragment new_fragment = MyFragment.newInstance("Added to begning  "+ (pageAdapter.getCount() + 1));         
            pageAdapter.add(0, new_fragment);
            current_page = selected_page;           
            //pageAdapter.notifyDataSetChanged();
        }

        return pageAdapter.getCount();


    }

    private ArrayList<Fragment> getFragments() {

        ArrayList<Fragment> fList = new ArrayList<Fragment>();

        fList.add(MyFragment.newInstance("Fragment 1"));
        fList.add(MyFragment.newInstance("Fragment 2"));
        fList.add(MyFragment.newInstance("Fragment 3"));
        fList.add(MyFragment.newInstance("Fragment 4"));
        fList.add(MyFragment.newInstance("Fragment 5"));

        return fList;
    }

    private class MyPageAdapter extends FragmentPagerAdapter {

        private ArrayList<Fragment> fragments;
        private ViewPager mPager;

        public MyPageAdapter(FragmentManager fm, ViewPager vp,
            ArrayList<Fragment> fragments) {
            super(fm);
            this.fragments = fragments;
            this.mPager = vp;


        }

        public void  add(int position,Fragment f){          
            fragments.add(position, f);
            this.notifyDataSetChanged();
        }


        @Override
        public Fragment getItem(int position) {
            return this.fragments.get(position);
        }

        @Override
        public int getCount() {
            return this.fragments.size();
        }


    }
}

My Fragment class

public class MyFragment extends Fragment {
public static final String EXTRA_MESSAGE = "EXTRA_MESSAGE";

public static final MyFragment newInstance(String message)
{
    MyFragment f = new MyFragment();
    Bundle bdl = new Bundle(1);
    bdl.putString(EXTRA_MESSAGE, message);
    f.setArguments(bdl);
    return f;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
    Bundle savedInstanceState) {

    String message = getArguments().getString(EXTRA_MESSAGE);
    View v = inflater.inflate(R.layout.myfragment_layout, container, false);
    TextView messageTextView = (TextView)v.findViewById(R.id.textView);
    messageTextView.setText(message);

    //return null;
    return v;
}


}
like image 589
Renjith K N Avatar asked Jun 07 '13 12:06

Renjith K N


1 Answers

I will explain here the way I did it in my case, I add to setup the same thing, except that I needed to swipe left and right between days and not months:

  1. I setup a minimum date and a maximum date that will become the limits for the dates to navigate. In my case I put big limits, from 1970 to 2050 to be sure I handle enough timeline. If we take an easier example with months, let's say 2012 to 2014, it means we will have 3 years * 12 months = 36 different positions available in the pager.

  2. When the application starts, by default my current fragment displays the current day, meaning for you, the current month. So I created a specific function on my app to get the position inside my timeline to get the position of the date selected in it. If we take again the example above, the position will therefore be 18.

To give you an idea, here is how I get the current day position in my Activity:

//position in the timeline
todayPosition = Days.daysBetween(new DateTime(MIN_DATE), new DateTime(getTodayDate())).getDays();

daysBetween is a function from the Joda Time library, I use it to get the number of days between the minimum date and the date selected (i.e. the position in the timeline).

Then in my onCreate function, I initialize the pager this way during the Activity creation:

pager.setCurrentItem(mApplication.getTodayPosition());

Here is the adapter, in case it inspires you:

public class MyFragmentPagerAdapter extends FragmentStatePagerAdapter{

private final int todayPosition;
private MyFragment currentFragment;
private final Calendar todayDate;

/** Constructor of the class */
public MyFragmentPagerAdapter(FragmentManager fm, int today_position, Calendar today_date) {
    super(fm);
    todayPosition = today_position;
    todayDate = (Calendar) today_date.clone();
}

/** This method will be invoked when a page is requested to create */
@Override
public Fragment getItem(int arg0) {     
    currentFragment = new MyFragment();
    Bundle data = new Bundle();

    data.putInt("current_page", arg0);
    currentFragment.setArguments(data);
    return currentFragment;
}

/** Returns the number of pages */
@Override
public int getCount() {     
    return MyApplication.TOTAL_NUMBER_OF_DAYS;
}

@Override
public CharSequence getPageTitle(int position) {
    Calendar newDate = (Calendar) todayDate.clone();

    int diffDays = position - todayPosition;
    newDate.add(Calendar.DATE, diffDays);

    return MyApplication.dateTitleFormat.format(newDate.getTime());
}   
}

I don't guarantee it is the best solution, but at least it is working.

like image 118
Yoann Hercouet Avatar answered Nov 13 '22 15:11

Yoann Hercouet