Как добавить страницу в начало ViewPager?

О моем приложении
Я разрабатываю приложение календаря. Хотите показать месяц с горизонтальной навигацией? Это означает бесконечную прокрутку. Пользователь может прокручивать вправо и влево ежемесячно до любой даты/месяца любого года. Я обнаружил, что ViewPager очень полезен для достижения этой цели (я действительно не знаю, какие другие используют полные методы). не хотите связываться с календарем устройства).

О проблеме
Я могу без проблем добавить новую страницу в конец моего пейджера View. Но если пользователь проводит пальцем влево, мне нужно добавить страницу в начало моего ViewPager. .когда я добавляю страницу в начало (нулевая позиция индекса), это заменит мою текущую страницу на нулевую позицию и сможет добавить только одну страницу (новые страницы не добавляются, я не знаю почему). И после добавления страницы в нулевую позицию я не могу добавить даже добавить страницу в конец пейджера просмотра, когда пользователь прокручивает вправо и достигает последней страницы. Принудительное закрытие происходит с ошибкой:

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

Простым предложением
Я хочу знать, как правильно добавлять страницы в начало и конец пейджера просмотра?

Код

Активность и адаптер

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


    }
}

Мой класс фрагментов

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


}

person Renjith K N    schedule 07.06.2013    source источник
comment
Ответ ниже - хороший способ, но он не добавляет страницу в начало просмотра пейджера, пожалуйста, помогите мне разобраться с этой проблемой, приглашаю всех поделиться своими идеями....   -  person Renjith K N    schedule 17.06.2013
comment
вы нашли какое-нибудь решение? у меня точно такая же проблема. tnx за обмен   -  person mehdok    schedule 05.11.2015


Ответы (1)


Я объясню здесь, как я сделал это в моем случае, я добавляю для настройки то же самое, за исключением того, что мне нужно было проводить пальцем влево и вправо между днями, а не месяцами:

  1. Я устанавливаю минимальную дату и максимальную дату, которые станут ограничениями для дат для навигации. В моем случае я установил большие ограничения, с 1970 по 2050 год, чтобы быть уверенным, что уложусь в достаточное количество времени. Если мы возьмем более простой пример с месяцами, скажем, с 2012 по 2014 год, это означает, что у нас будет 3 года * 12 месяцев = 36 различных позиций, доступных в пейджере.

  2. При запуске приложения мой текущий фрагмент по умолчанию отображает текущий день, то есть для вас текущий месяц. Поэтому я создал специальную функцию в своем приложении, чтобы получить позицию внутри моей временной шкалы, чтобы получить позицию выбранной в ней даты. Если мы снова возьмем приведенный выше пример, то позиция будет 18.

Чтобы дать вам представление, вот как я получаю текущую дневную позицию в моем Activity:

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

daysBetween — это функция из библиотеки Joda Time, я использую ее для получения количества дней между минимальной датой и выбранной датой (т. е. положением на временной шкале).

Затем в моей функции onCreate я инициализирую пейджер таким образом во время создания Activity:

pager.setCurrentItem(mApplication.getTodayPosition());

Вот адаптер, если он вас вдохновит:

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

Я не гарантирую, что это лучшее решение, но, по крайней мере, оно работает.

person Yoann Hercouet    schedule 07.06.2013
comment
Спасибо, Йоанн, я думаю, у вас большое количество страниц, а как насчет производительности, чувствуете ли вы какую-либо заметную разницу в производительности? Обязательно попробую ваши предложения ... Спасибо :) - person Renjith K N; 07.06.2013
comment
Скорость хорошая, надо использовать FragmentStatePagerAdapter а не FragmentPagerAdapter. Первый лучше справляется с большим количеством страниц, он будет хранить в памяти только активные фрагменты: developer.android.com/reference/android/support/v4/app/ - person Yoann Hercouet; 07.06.2013