4
6

More than 3 years have passed since last update.

ViewPager2とTabLayoutを簡単に実装する

Last updated at Posted at 2020-09-01

はじめに

ViewPager2を実装する際、今までは複数のViewに対してその同数レイアウトファイルを作成していました。
今回は一つのレイアウトファイルで表示できたので紹介します。
ViewPager2実装するのが初めての方にもTabLayoutMediatorFragmentManagerを理解する助けになればと思います。

全体を見たい方向けにサンプルのリポジトリ載せときます。
https://github.com/tomoya-s-101/viewpager2

環境

OS: macOS Catalina v10.15.6
IDE: Android Studio v4.0.1

導入

TabLayoutを使用できるようにするために、build.gradleにmaterial-componentsライブラリを追加します。

build.gradle
implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01"
implementation 'com.google.android.material:material:1.2.0'

実装

今回は一つのフラグメントレイアウトで画像の色とテキストの切り替えをViewPager2を使い表示します。
output.gif

レイアウト

bindingの実装をしたいので、layoutタグで囲います。
tabIndicatorGravityでインジケーターの位置を指定できます。
TabLayoutリファレンス

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            app:tabIndicatorGravity="stretch"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent">
        </com.google.android.material.tabs.TabLayout>

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager2"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toTopOf="@id/tab_layout"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ViewPager2で表示するレイアウトを作ります。
stringとcolorのリソースも準備してください。

fragment_color.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/fragment_color"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tab_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TabTextView"
            android:textColor="@color/white"
            android:textSize="48sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Fragment

表示させたいリストのインスタンスを生むことで、一つのレイアウトで切り替えが可能になります。

ColorFragment.kt
class ColorFragment: Fragment() {
    companion object {
        private const val ARGS_POSITION = "position"
        fun newInstance (position: Int) = ColorFragment().apply {
            arguments = Bundle().apply {
                putInt(ARGS_POSITION, position)
            }
        }
    }

    private lateinit var binding: FragmentColorBinding

    private val position: Int by lazy {
        arguments?.let {
            it[ARGS_POSITION] as Int
        }?:0
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_color, container, false)
        return binding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        binding.apply {
            when(position) {
                0 -> {
                    tabTextView.setText(R.string.text_red)
                    fragmentColor.setBackgroundResource(R.color.red)
                }
                1 -> {
                    tabTextView.setText(R.string.text_blue)
                    fragmentColor.setBackgroundResource(R.color.blue)
                }
                2 -> {
                    tabTextView.setText(R.string.text_green)
                    fragmentColor.setBackgroundResource(R.color.green)
                }
                else -> {
                    tabTextView.setText(R.string.text_yellow)
                    fragmentColor.setBackgroundResource(R.color.yellow)
                }
            }
        }
    }
}

Adapter

FragmentActivityを使用するため、FragmentManagerを呼び出します。
FragmentManagerリファレンス

ViewPager2Adapter.kt
class ViewPager2Adapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
    FragmentStateAdapter(fragmentManager, lifecycle) {

    private val fragments: ArrayList<Fragment> = arrayListOf(
        ColorFragment.newInstance(0),
        ColorFragment.newInstance(1),
        ColorFragment.newInstance(2),
        ColorFragment.newInstance(3)
    )

    override fun getItemCount(): Int {
        return fragments.size
    }

    override fun createFragment(position: Int): Fragment {
        return fragments[position]
    }
}

Activity

TabLayoutMediatorでTabLaoutとViewPager2を引数で渡すことで、スクロールとインジケーターがリンクします。
TabLayoutMediatorリファレンス

MainActivity.kt
class MainActivity : AppCompatActivity() {
    companion object {
        fun callingIntent(context: Context) = Intent(context, MainActivity::class.java)
    }

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView<ActivityMainBinding>(
            this, R.layout.activity_main
        ).apply {
            viewpager2.adapter = ViewPager2Adapter(supportFragmentManager, lifecycle)

            TabLayoutMediator(tabLayout, viewpager2) { tab, position ->
            }.attach()
        }
    }
}

おわりに

他にもViewPager2では、縦方向のスクロールなどアクティブな実装が簡単にできるみたいです。
ドキュメント

閲覧ありがとうございました。
2020年7月からエンジニアとして働き始めた見習いですので、拙い点ございます。
間違いやより適切な方法ありましたら、コメントお願いします。
今後も記事を投稿していくので、是非よろしくお願い致します。

参考

https://developer.android.com/reference/com/google/android/material/tabs/TabLayout
https://developer.android.com/reference/kotlin/androidx/fragment/app/FragmentManager?hl=ja
https://developer.android.com/reference/com/google/android/material/tabs/TabLayoutMediator
https://developer.android.com/training/animation/vp2-migration?hl=ja

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6