ViewPagerとPagerAdapterでスワイプビューを作ってみる


内容

ViewPagerをとPagerAdapter使って、右に左にひゅいっとスワイプして遷移するビューの練習です。
Tabによる遷移も加えておきました。

作るもの

すごく単純。ネズミさんから始まりイノシシさんで終わります。
数字の表示が崩れているのはご勘弁を。

ポイント

ViewPagerとTabLayoutを定義

ポイントと言うほどのものでもないですが、ViewGroupとTabLayoutを定義します。

activity_zodiac_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

</androidx.viewpager.widget.ViewPager>

PagerAdapterをセット

スワイプビューを作成するためにPagerAdapterをViewPagerにセットします。
adapterなので、RecyclerView.Adapterにちょっと似てますね。
PageAdapterには3つのメソッドが定義されています。

  • getCount()
    全体の数を取得する

  • getItem(position)
    指定した位置にあるFragmentを返す

  • getPageTitle(position)
    指定した位置にあるTab用の表示を返す

FragmentPagerAdapterの特徴

ここではPageAdapterの実装として FragmentPagerAdapter を使っています。
役割をほぼ同じですが、一方で FragmentStatePagerAdapter というのもあります。
これらの違いと使い方は以下のような感じ。

特徴 使い所
FragmentStatePagerAdapter 前後のページ以外はメモリから破棄される 表示する数が多いもの(とりあえずこっちが安全かも)
FragmentPagerAdapter メモリが破棄されず残る 固定で少ないもの(Tab系はこっちが良さげ?)

今回は12個で固定だったので、FragmentPagerAdapterを使いました。
(12個は多い部類説?)

FragmentStatePagerAdapterにおいてデフォルトでは前後の1ページですが、setOffscreenPageLimit(int) によってロードする前後のページ数を調整できます。

ZodiacPagerActivity.kt
class ZodiacPagerActivity : AppCompatActivity() {

    private lateinit var mViewPager: ViewPager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_zodiac_pager)

        mViewPager = findViewById(R.id.view_pager)

        val fragmentManager = supportFragmentManager
        mViewPager.adapter = object : FragmentPagerAdapter(fragmentManager) {
            override fun getItem(i: Int): Fragment {
                val fragment = ZodiacFragment()
                fragment.arguments = Bundle().apply {
                    putInt(ARG_OBJECT, i)
                }
                return fragment
            }

            override fun getCount(): Int {
                return 12
            }

            override fun getPageTitle(position: Int): CharSequence? {
                return "${position + 1}"
            }

        }
    }
}

private const val ARG_OBJECT = "object"

class ZodiacFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_zodiac, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val textView: TextView = view.findViewById(R.id.zodiacText)
        val i = arguments?.getInt(ARG_OBJECT)
        textView.text = getAnimalName(i)
    }

    private fun getAnimalName(i: Int?): String {
        return when (i) {
            0 -> "子"
            1 -> "丑"
            2 -> "寅"
            3 -> "卯"
            4 -> "辰"
            5 -> "巳"
            6 -> "午"
            7 -> "未"
            8 -> "申"
            9 -> "酉"
            10 -> "戌"
            11 -> "亥"
            else -> "神"
        }
    }
}

参考

Create swipe views with tabs
Android Programming: The Big Nerd Ranch Guide (3rd Edition) (Big Nerd Ranch Guides)