この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
ViewPagerの無限スクロールは、色々な方がライブラリを提供しています。
しかし、PagerTabStripと併用できるものが見当たらないため、作成しました。
実装
InfiniteViewPager.java
public class InfiniteViewPager extends ViewPager {
InfinitePagerAdapter mInfinitePagerAdapter;
public InfiniteViewPager(Context context) {
super(context);
}
public InfiniteViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setAdapter(PagerAdapter adapter) {
mInfinitePagerAdapter = (InfinitePagerAdapter) adapter;
super.setAdapter(adapter);
setCurrentItem(0); // 初期表示位置
}
@Override
public void setCurrentItem(int item) {
// 第2引数をtrueにする場合、
// アニメーションが不自然になるので、スクロールイベントでの対応が必要になる
setCurrentItem(item, false);
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
super.setCurrentItem(
item % mInfinitePagerAdapter.getRealCount() + getOffsetAmount(),
smoothScroll
);
}
@Override
public int getCurrentItem() {
// Viewの表示などで利用されるので、値を誤魔化す
return super.getCurrentItem() % mInfinitePagerAdapter.getRealCount();
}
private int getOffsetAmount() {
// 開始位置を真ん中に近い数値にすることで、初期表示時に左へスクロールできるようにする
// FIXME ページ数によっては、良い感じに調整してください。
return mInfinitePagerAdapter.getRealCount() * 100;
}
}
InfinitePagerAdapter.java
/**
* 表示する各クラスで、実装を行えるようにする
*/
public abstract class InfinitePagerAdapter extends FragmentPagerAdapter {
private int mRealCount = -1;
public InfinitePagerAdapter(FragmentManager fm) {
super(fm);
}
/**
* 表示するフラグメントを実装する
*/
@Override
public abstract Fragment getItem(int position);
/**
* 表示するタイトルを設定する
*/
@Override
public abstract CharSequence getPageTitle(int position);
@Override
public int getCount() {
// return Integer.MAX_VALUE を利用しているライブラリが多いですが、
// あまり大きすぎる値を設定すると、PagerTabStripと併用した際に
// タブをクリックすると、フリーズしてしまう。
return 1000;
}
public void setRealCount(int count) {
mRealCount = count;
}
public int getRealCount() {
return mRealCount != -1 ? mRealCount : 0;
}
protected int convertToDummyPosition(int realPosition) {
return realPosition % getRealCount();
}
}
View側の実装(適宜良い感じに)
<com.sample.view.InfiniteViewPager
android:id="@+id/sample_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v4.view.PagerTabStrip
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</com.sample.view.InfiniteViewPager>
@Nullable
@Override
public View onCreateView(// 省略) {
// 省略
InfinitePagerAdapter adapter = new SampleAdapter(getChildFragmentManager());
adapter.setRealCount(3); // 実際のページ数
mViewPager.setAdapter(adapter);
// 省略
}
// 実装クラス
private static final class SampleAdapter extends InfinitePagerAdapter {
public SampleAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return SampleFragment.newInstance();
}
@Override
public CharSequence getPageTitle(int position) {
// 実際には大きな値がpositionに来るので
// ダミー値に変換する
switch (convertToDummyPosition(position)) {
case 0:
return "0番目タイトル";
case 1:
return "1番目タイトル";
case 2:
return "2番目タイトル";
default:
return "error";
}
}
}
補足
今回の実装方法では、実質無限スクロールです。
getCountにて大きい値を設定し、getOffsetAmountで表示開始位置を真ん中に近い数値にしています。
その為、何回もスライドすれば限界まで到達します。
ダミーを両サイドに用意(C' A B C A')して、スクロールイベントで調整する方法もありますが
シンプルに実装できることと、PagerTabStrip・PagerTitleStripをそのまま導入できるので、ご紹介致しました。
あとがき
需要も多いので、公式で対応してくれると嬉しいのですが・・・
app:isLoop="true" と書くだけで出来るようになって欲しいですね(笑)