ViewPager2, TabLayoutを用いてタブ付きスワイプビューを作成。そのタブを無限ループさせる。
ViewPager2, TabLayoutを用いてタブ付きスワイプビューを作成する。さらにそのタブ,スワイプを無限ループできるようにする。
参考にしたのはこれら
もちろんkotlinで実装します。バージョンは1.4.21
主要な登場クラスはViewPager2, TabLayout, FragmentStateAdapter, Fragment
仕組みとしては、表示したいものが10ページあるとしたら、
[10][1][2][3][4][5][6][7][8][9][10][1]
つまりは実際のページ数に+2して、両端に実際の最後のページと最初のページをくっつけるということ。
FragmentStateAdapter側の実装
private val REAL_PAGE_SIZE = 10 class CollectionAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { override fun getItemCount(): Int = REAL_PAGE_SIZE + 2 fun getRealCount() = REAL_PAGE_SIZE fun getRealPosition(position: Int): Int { return when (position) { 0 -> getRealCount() - 1 getRealCount() + 1 -> 0 else -> position - 1 } } // Return a NEW fragment instance in createFragmt override fun createFragment(position: Int): Fragment { val i = getRealPosition(position) return ItemFragment.newInstance("$i") } }
ViewPager2,TabLayout側の実装
class BlankFragment : Fragment() { private var _binding: FragmentBlankBinding? = null private val binding get() = _binding!! private lateinit var collectionAdapter: CollectionAdapter private lateinit var viewPager: ViewPager2 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentBlankBinding.inflate(inflater, container, false) return binding.root } override fun onDestroyView() { super.onDestroyView() _binding = null } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) collectionAdapter = CollectionAdapter(this) viewPager = binding.pager viewPager.apply { adapter = collectionAdapter registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { private var realPosition = -1 override fun onPageScrollStateChanged(state: Int) { if (state == ViewPager2.SCROLL_STATE_IDLE && realPosition >= 0) { viewPager.setCurrentItem(realPosition, false) realPosition = -1 } } override fun onPageSelected(position: Int) { when (position) { 0 -> realPosition = collectionAdapter.getRealCount() collectionAdapter.getRealCount() + 1 -> realPosition = 1 else -> { } } } }) setCurrentItem(1, false) } val tabLayout = binding.tabLayout tabLayout.tabMode = TabLayout.MODE_SCROLLABLE TabLayoutMediator(tabLayout, viewPager) { tab, position -> val i = collectionAdapter.getRealPosition(position) tab.text = "PAGE ${(i + 1)}" }.attach() } companion object { ... } }
ViewPager2を持つFragmentのxml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".BlankFragment"> <com.google.android.material.tabs.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout>
このリポジトリ GitHub - ochim/extend-affirmationsで使っています。
以上