[kotlin] ViewPagerをボタンで切り替える

#今回やること
これ↓  
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520167/d513baa6-274d-76ec-1eff-ea80fdc2e216.gif" width=340>


ViewPagerを使ってフラグメントの切り替えをスワイプとボタンでできるようにする。(kotlinで書きます)  `OnPageChangeListener`を使います
※今回はViewPager実装済みとしてやっていくのでアダプターなどには触れません。まだ実装してないよという方はよろしければこちら参考に。

[[kotlin] ViewPagerでフラグメントを切り替える](https://qiita.com/YS-BETA/items/091a84961d5b56fced2b)


#ボタンを作成
レイアウトファイルにボタンを作る。

```xml:activity_main
<?xml version="1.0" encoding="utf-8"?>
<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">

    <Button
        android:id="@+id/nextPageBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="次へ"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.9"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.95" />

    <Button
        android:id="@+id/prevPageBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="前へ"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.1"
        app:layout_constraintStart_toStartOf="@+id/viewPager"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.95" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" >

    </androidx.viewpager.widget.ViewPager>
</androidx.constraintlayout.widget.ConstraintLayout>
```

ViewPagerに加えて「次へ」「前へ」の２つのボタンをつける。
ボタンは全フラグメント共通で表示したいのでフラグメントのレイアウトxmlファイルではなくViewPagerを実装しているレイアウトxmlファイルにつける。

#リスナーをセット
上記で作成したボタンにリスナーをセットする

```kotlin:MainActivity.kt
package com.example.viewpagersample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

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


        /// フラグメントのリストを作成
        val fragmentList = arrayListOf<Fragment>(
            Sample1Fragment(),
            Sample2Fragment(),
            Sample3Fragment()
        )

        /// adapterのインスタンス生成
        val adapter = SamplePagerAdapter(supportFragmentManager, fragmentList)
        viewPager.adapter = adapter

        /// ページ遷移のリスナーをセット
        nextPageBtn.setOnClickListener {
            // ページを1つ進める
            viewPager.currentItem += 1
        }
        prevPageBtn.setOnClickListener {
            // ページを1つ戻す
            viewPager.currentItem -= 1
        }
    }
}

```
とりあえず完成。
ただしこのままだと一番最初のぺージや最後のページでも「次へ」「前へ」ボタンが表示されるので`OnPageChangeListener`を使う

#OnPageChangeListener
`OnPageChangeListener`: ViewPagerに用意されているメソッドの一つ

似たようなものに`SimpleOnPageChangeListener`がある。こちらはimplementsしなければならないメソッドがより少なく`onPageSelected`だけになっている。

上記のコードに以下を追加する。

```kotlin:MainActivity.kt
 /// prevBtnの初期visibility
        prevPageBtn.isVisible = false

        /// スクロール中の変更処理
        viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            /// implementする
            override fun onPageSelected(position: Int) {
                /// btnの表示制御（端では表示しない）
                prevPageBtn.isVisible = position != 0
                nextPageBtn.isVisible = position != fragmentList.size - 1
            }

            override fun onPageScrollStateChanged(state: Int) {
            }

            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
            }
        })
```
`onPageSelected`のタイミングでposition(その時のページ)が最初と最後の時ボタンをINVISIBLEにする
### OnPageChangeListener メソッド

| メソッド名       |       呼び出されるタイミング |
|:-----------------|:------------------:|
| onPageSelected             |       新しいページが選択され終わったとき |  
| onPageScrollStateChanged| スクロールの状態が変わった時（多分スクロールされ始めた時とスクロールを終えたとき「状態：スクローリング」「状態：停止」って感じで動く）            |  
|onPageScrolled|   ページがスクロールされている最中           |  
`onPageScrollStateChanged`のとこだけあんまり自信がないので間違ってたら教えてください。

#おわり
`onPageSelected`しか使ってないけどなんとなくで`OnPageChangeListener`使いました。
kotlin好き。
今回フリー素材のイラストを利用させていただきました。(三日月アルペジオ)