概要
- スワイプでページ送りが出来る
- しかもページの最後まで行った時に、続きのページをリクエストしたりする
使うもの
- 管理するActivity
- FragmentStatePagerAdapterを拡張したクラス
- ページ表示されるFragment
さんぷるシチュエーション
- 投稿IDのリストが有ったとして、Fragmentでそれの詳細を表示、スワイプで次の投稿の詳細を見たりする時に
作り方
PagerActivity
- 遷移前の画面から、選択したアイテムのIdとかAPIのタイプとかページ数とか投稿Idのリストとかを受け取る
- ViewPagerとFragmentStatePagerを生成
- ViewPager.OnPageChangeListenerをインプリ
- onPageScrollStateChanged()でViewPager.SCROLL_STATE_IDLEの時に残りページをチェック
- 現在のページを取得 ViewPager#getCurrentItem()
- 続きがあるのかを判定 CustomFragmentStatePagerAdapter#getCount()
ViewPagerではデフォルトで1ページ先まで生成しているので、
if (currentIndex == mPagerAdapter.getCount() - 3)
とかで続きの有無をチェックする。(getCount()から-3で判定しているのは、続きのリクエストが早めに返ってきてほしいから)
この条件に引っかかったら、続きの投稿を取得するAPI叩いて返ってきたらPagerAdapterの持つページリストに追加する。
CustomFragmentStatePagerAdapter
- ページに対応する投稿Idとページを追加するメソッドを追加。
PageFragment
- PageFragment#newInstance()で投稿Idとかを渡してFragment側で詳細をリクエスト
- このFragmentでgetActivity()するとnullになることが有るので、onAttach(Activity)でActivityをWeakReferenceでフィールドに持つ
実際のぶつ
抜粋
PagerActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pager);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
// 遷移元のページによって使用するAPIが異なるので、それを分岐するためのオブジェクトとか諸々を受取ります
mType = getIntent().getExtras().getParcelable("apiType");
initViewPagerAdapter();
initRequestParams();
}
// PagerAdapterの準備
public void initViewPagerAdapter(){
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setVisibility(View.VISIBLE);
mPagerAdapter = new CustomFragmentStatePagerAdapter(getSupportFragmentManager(), mIdList);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(getCurrentPosition(mType.getCurrentId()));
mViewPager.setOnPageChangeListener(this);
}
public int getCurrentPosition(String itemId){
return mIdList.indexOf(itemId);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
// ページが切り替わったタイミングをハンドルする
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
int currentIndex = mViewPager.getCurrentItem();
if (currentIndex != 0 && currentIndex != mPagerAdapter.getCount() -3)
return;
// 最後まで来た時は新しくデータを取得する
if (currentIndex == mPagerAdapter.getCount() - 3) {
incrementPager();
requestNextItems();
}
}
}
// 以降、省略
CustomFragmentStatePagerAdapter.java
public class CustomFragmentStatePagerAdapter extends FragmentStatePagerAdapter{
private List<String> mPageIdList;
public CustomFragmentStatePagerAdapter(FragmentManager fm,List<String> pageIdList) {
super(fm);
this.mPageIdList = pageIdList;
}
@Override
public Fragment getItem(int position) {
return SwipeDetailFragment.newInstance(mPageIdList.get(position));
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public int getCount() {
return mPageIdList.size();
}
public void addPage(List<String> pages){
mPageIdList.addAll(pages);
}
}
PageFragment.java
// 前略
// FragmentからgetActivityでnullが返る事があるのでフィールドに持っておく
public class PageFragment extends Fragment{
private WeakReference<Activity> mActivityRef;
public PageFragment() {
}
public static Fragment newInstance(String postId){
Bundle bundle = new Bundle();
bundle.putString("POST_ID", postId);
PageFragment fragment = new PageFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivityRef = new WeakReference<>(activity);
}
// 以降、省略
メモ
- PagerAdapterは怖い
- 削除とかしたくない
- FragmentでPicassoを使って画像リクエストして死んだ原因になかなか気付けなかった
- FragmentがActivityもってるのはどうなの
- 実際に使った時に、Fragment側で一部Viewのリサイズ(requestLayout)したら?Fragmentを表示した時の位置が下にずれてうざい