【Android】ViewPagerのページを動的に追加する
ViewPagerのページに表示するデータを最初にセットせずに逐次読み込みたかったので
一番端のページに到達したら新しくデータを追加し新規ページが追加される処理を入れてみた。
流れ
ページが端に到達したか確認
↓
データを追加しAdapterを更新
実装
MainActivity.java
public class MainActivity extends FragmentActivity implements OnPageChangeListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初期データ ArrayList<Integer> items = new ArrayList<Integer>(); items.add(0); items.add(1); items.add(2); MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager()); adapter.addAll(items); final ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager); viewPager.setAdapter(adapter); viewPager.setCurrentItem(1); viewPager.setOnPageChangeListener(this); } @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) { ViewPager viewPager = (ViewPager)findViewById(R.id.viewPager); MyPagerAdapter adapter = (MyPagerAdapter) viewPager.getAdapter(); ArrayList<Integer> indexes = adapter.getAll(); int currentPage = viewPager.getCurrentItem(); if( currentPage != 0 && currentPage != indexes.size() - 1){ //最初でも最後のページでもない場合処理を抜ける return; } int nextPage = 0; if(currentPage == 0){ //最初のページに到達 nextPage = 1; indexes.add(0, indexes.get(0) - 1); //1ページ目は既に存在するため、Fragmentを全て破棄する adapter.destroyAllItem(viewPager); adapter.notifyDataSetChanged(); }else if(currentPage == indexes.size() - 1){ //最後のページに到達 nextPage = currentPage; indexes.add(indexes.get(indexes.size() - 1) + 1); } adapter.addAll(indexes); viewPager.setAdapter(adapter); viewPager.setCurrentItem(nextPage); } } }
ViewPagerにsetOnPageChangeListenerをセットしてonPageScrollStateChangedで状態を取る。
stateがSCROLL_STATE_IDLEの場合にページの移動が完了しているので最初か最後のページかを判断して新しくページを追加する。
最初のページに到達し新しくページを追加した場合は既にあるFragmentが使い回されてページが更新されないためFragmentを破棄する処理を入れる。
onPageSelectedでなくonPageScrollStateChangedを使用するのがミソ。
onPageSelectedだと次のページが選択されたときに呼び出されるようで
ページの移動が完了したときではないみたいでした。
なので挙動が不自然になる。
FragmentとAdapterは以下
MyFragment.java
public class MyFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_pageritem, container, false); Bundle bundle = getArguments(); int index = bundle.getInt("INDEX"); TextView textView = (TextView)view.findViewById(R.id.textView1); textView.setText("Index:" + index); return view; } }
MyPagerAdapter.java
public class MyPagerAdapter extends FragmentPagerAdapter { private ArrayList<Integer> mIndexes = new ArrayList<Integer>(); public MyPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { Bundle bundle = new Bundle(); bundle.putInt("INDEX", mIndexes.get(position)); MyFragment fragment = new MyFragment(); fragment.setArguments(bundle); return fragment; } @Override public int getCount() { return mIndexes.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } public void destroyAllItem(ViewPager pager) { for (int i = 0; i < getCount() - 1; i++) { try { Object obj = this.instantiateItem(pager, i); if (obj != null) destroyItem(pager, i, obj); } catch (Exception e) { } } } @Override public void destroyItem(ViewGroup container, int position, Object object) { super.destroyItem(container, position, object); if (position <= getCount()) { FragmentManager manager = ((Fragment) object).getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); trans.remove((Fragment) object); trans.commit(); } } public void addAll(ArrayList<Integer> indexes) { mIndexes = indexes; } public ArrayList<Integer> getAll() { return mIndexes; } }
FragmentPagerAdapterのFragment破棄部分は以下で書いています。
【Android】FragmentPagerAdapterでFragmentを更新する - Kuwappブログ-アプリ開発記