昔々あるところに無限ループを実現したViewPagerを作った人がいました。
public class LoopViewPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
}
カウントをひたすら大きくして、setCurrentItemで中央値に設定。
無限ループするように見せかけるやつ。
実際、この仕組で無限ループさせてる人って結構いると思う。
昔これで実装してたし。
で、また無限ループなViewPagerを作ることになってググったら良い実装方法があった。
仕組み的にはこんな感じにページを配置する。
5ページあるとしたら、、、。
[E][A][B][C][D][E][A]
要は実際のページ数に+2して両端に実際の最初と最後をくっつける。
当時の自分、なんでこれ思いつかなかったんだろうね。
ってことで実装。
実装
Adapterを作成
class LoopPagerAdapter(private var items: List<BannerModel>) : PagerAdapter() {
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val view = LayoutInflater.from(container.context).inflate(R.layout.pager_image, null)
Glide.with(container.context)
.load(items[getRealPosition(position)].imageUrl)
.into(view.pagerImageView)
container.addView(view)
return view
}
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
container.removeView(`object` as View)
}
override fun isViewFromObject(p0: View, p1: Any) = p0 == p1
override fun getCount() = items.size + 2
fun getRealCount() = items.size
private fun getRealPosition(pagerPosition: Int) = when (pagerPosition) {
0 -> getRealCount() - 1
getRealCount() + 1 -> 0
else -> pagerPosition - 1
}
}
getCount()で返すのは両端に仮ページを載せたいから+2する。
実際のカウントほしいからgetRealCount()を用意。
アイテムとPagerのポジションがずれるので実際のポジションを取るgetRealPosition()を用意。
AdapterはこれでOK。
BannerModelは空気読んでくださいw
ViewPager側の設定
//
viewPager.apply {
adapter = LoopPagerAdapter(mutableListOf<BannerModel>().apply {
add(BannerModel().apply {
imageUrl = "https://placegoat.com/300/200"
})
add(BannerModel().apply {
imageUrl = "https://placekitten.com/300/200"
})
add(BannerModel().apply {
imageUrl = "https://www.placecage.com/300/200"
})
add(BannerModel().apply {
imageUrl = "https://stevensegallery.com/300/200"
})
add(BannerModel().apply {
imageUrl = "https://placeimg.com/300/200/people"
})
})
addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
private var realPosition = -1
override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {}
override fun onPageScrollStateChanged(state: Int) {
if (state == ViewPager.SCROLL_STATE_IDLE && realPosition >= 0) {
viewPager.setCurrentItem(realPosition, false)
realPosition = -1
}
}
override fun onPageSelected(position: Int) {
when (position) {
0 -> realPosition = (adapter as LoopPagerAdapter).getRealCount()
(adapter as LoopPagerAdapter).getRealCount() + 1 -> realPosition = 1
else -> {
}
}
}
})
adapter?.notifyDataSetChanged()
viewPager.setCurrentItem(1, false)
}
onPageSelected()で実際のポジションを保持。
onPageScrollStateChanged()でスクロール終わったタイミングで実際のページにアニメーション無しでこっそりとページ遷移させる。
で、初期位置は1ページ目とする。
Adapterに渡しているURLは以下を参考にしたw