Help us understand the problem. What is going on with this article?

ViewPagerのページ数を動的に変更するためのPagerAdapterライブラリを作りました

More than 3 years have passed since last update.

ViewPagerのページ数を動的に変更するためのライブラリを作りました。(https://github.com/takaaki7/ArrayPagerAdapter

イチから実装するのが結構面倒だからです。(後述)

ArrayFragmentStatePagerAdapter, ArrayFragmentPagerAdapter, ArrayViewPagerAdapterの3つのアダプターが使えます。

ListViewなどのシンプルな利用に使われるandroid.widget.ArrayAdapter<T>を参考にしました。

使い方

ArrayFragmentStatePagerAdapter<T>の使い方の例です。

@Override
protected void onCreate(Bundle savedInstanceState) {
        /** ... **/
    adapter = new MyStatePagerAdapter(getSupportFragmentManager()
                            , new String[]{"1", "2", "3"});
    ((ViewPager)findViewById(R.id.view_pager)).setAdapter(adapter);
     adapter.add("4");
     adapter.remove(0);
}

class MyStatePagerAdapter extends ArrayFragmentStatePagerAdapter<String> {

    public MyStatePagerAdapter(FragmentManager fm, String[] datas) {
        super(fm, datas);
    }

    @Override
    public Fragment getFragment(String item, int position) {
        return MyFragment.newInstance(item);
    }
}

アダプターに対しadd(String item)remove(int position)を呼べば細かいことは気にせずともデータを動的に増減させることができ、それに対応していらないページの削除などを内部でよしなにやってくれます。
ArrayFragmentPagerAdapterArrayViewPagerAdapterも同じような方法で使えます。

詳しくは
https://github.com/takaaki7/ArrayPagerAdapter
のデモなどをご覧ください。

なぜ

なぜ動的なページの増減が難しいのか。

おさらいとして、ViewPagerを使う場合、PagerAdapterFragmentPagerAdapterFragmentStatePagerAdapterの3種類のアダプターを使う方法があります。

例えばFragmentStatePagerAdapterはこのように利用すると思います。

public static class MyAdapter extends FragmentStatePagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(position);
    }
}    

しかし、動的にページを増減させる場合次のようなことも意識しないけいけません。

1 int getItemPosition(Object object)を実装する

getItemPositionViewPagerから呼ばれるメソッドです。これはobject(フラグメントとか)の位置が変わった場合は新しい位置を返し、変わってない場合はPOSITION_UNCHANGEDを返し、objectが既にない場合はPOSITION_NONEを返す必要があります。
ViewPagerのコードを見ると、notifyDataSetChanged()が呼ばれた時に現在保持している全objectmAdapter.getItemPosition(object)に渡して呼び出し、POSITION_NONEや新しい位置が返ってきた場合はページを作り直したり位置を計算し直したりしているようです。

デフォルトのPagerAdapterたちは動的なデータの増減を想定して作られていないので常時POSITION_UNCHANGEDを返しています。

(メソッド名が若干わかりにくい。。。)

2.1 FragmentStatePagerの不具合

詳しくはコメント欄に投稿しましたが、FragmentStatePagerの場合はgetItemPosition(object)if(object == 消したいフラグメント){ return POSITION_NONE } else { objectの位置
}
のような感じでgetItemPosition()を実装するだけでは他のページとの整合性がうまく取れず、表示がおかしくなる場合があるようです。おそらくFragmentStatePagerの不具合によるものです。

2.2 FragmentPagerAdapterの場合、一度追加したFragmentを取り除かなければならない

FragmentPagerAdapterの内部では一度追加したFragmentremove()を行っておらず、ページが隠れて破棄される時はdetach()(UIを削除する)をしているだけなのでFragmentManagerの管理下でメモリに残ります。正しく削除するためにdetach()ではなくremove()をしたいところです。

どうやって

getItemPosition()で常時POSITION_NONEを返すようにしたり、表示する内容を変更した時にアダプターを再度作ってセットし直す方法とかもあるようですが、そうすると毎回全て一からインスタンス化し直すことになるのでエコじゃないと思います。

ArrayPagerAdapterは外から渡されたデータをリストとして保存し管理することでgetItemPositionを正しく実装し、元のFragmentStatePagerAdapterFragmentPagerAdapterなどを改良することで表示中のページの削除や追加を実装しました。

よかったら使ってみてください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした