[Android]BottomSheetの実装

はじめに
====
BottomSheetを実装をまとめます。

BottomSheetとは
====
Android Support Library 23.2で追加されていたようです。
https://android-developers.googleblog.com/2016/02/android-support-library-232.html

下から出てくるやつで、Google MapやSpotifyなんかで見かけます。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr"><a href="https://twitter.com/hashtag/Android?src=hash&amp;ref_src=twsrc%5Etfw"></a> <a href="https://t.co/Z35caXiBL0">pic.twitter.com/Z35caXiBL0</a></p>&mdash;  <a href="https://twitter.com/kurram_kurram/status/1248819076677259264?ref_src=twsrc%5Etfw"></a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


Gradle
===

Gradleに以下を追加します。

``` build.gradle
dependencies {
    implementation 'com.google.android.material:material:1.1.0'
}
```

Layout
===
Layoutは以下のようになります。

```xml:activity_main.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">

    (省略)

   <LinearLayout
        android:id="@+id/bottom_sheet_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorPrimary"
        app:behavior_peekHeight="120dp"
        app:behavior_hideable="true"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Bottom Sheet Layout Foreground" />

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
```
LinearLayoutをネストしたよくある画面構成とほとんど同じですが、
LinearLayoutに以下を指定することでボトムシートとなります。

```
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
```

###縮小時（collapsed時）の高さを指定
layoutファイルで指定

```
app:behavior_peekHeight
```

ソース上で指定

```kotlin:MainActivity.kt
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet)
behavior.peekHeight = 200
```

###下までスワイプした時に非表示化

layoutファイルで指定

```
app:behavior_hideable="true"
```

ソース上で指定

```MainActivity.kt
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet)
behavior.isHideable = true
```

ソース
===

具体的なソースは以下のようになります。
実装の内容はコメントに記載していきます。

```MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var mBottomSheet: BottomSheetBehavior<LinearLayout>

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

        val textView = findViewById<TextView>(R.id.text_view)
        val bottomSheet = findViewById<LinearLayout>(R.id.bottom_sheet_layout)
        // ボトムシートのインスタンス生成
        mBottomSheet = BottomSheetBehavior.from(bottomSheet)

        // 背景のテキストをクリックで状態変更
        textView.setOnClickListener { onTextClicked(it) }
    }

    private fun onTextClicked(view: View) {
        when (view.id) {
            R.id.text_view ->
                if (mBottomSheet.state != BottomSheetBehavior.STATE_EXPANDED) {
                    // 全画面化
                    mBottomSheet.state = BottomSheetBehavior.STATE_EXPANDED
                } else {
                    // 縮小化（peekHeightの高さ）
                    mBottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED
                }
        }
    }
}

```

ボトムシートの状態変化
===
Android Support LibraryではBottomSheetBehavior#setBottomSheetCallbackのAPIで変更を受けていましたが、
AndroidXでは、BottomSheetBehavior#addBottomSheetCallbackのAPIで変更を受けます。

```MainActivity.kt 
val bottomSheet = findViewById<LinearLayout>(R.id.bottom_sheet_layout)
BottomsheetBehavior behavior= BottomSheetBehavior.from(bottomSheet)

behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
    override fun onSlide(bottomSheet: View, slideOffset: Float) {

    }

    override fun onStateChanged(bottomSheet: View, newState: Int) {
        // 状態変化を通知
        Log.d("MainActivity", "#onCreate\$onStateChanged state = $newState")
    }
})
```


|値|定数|状態|
|----|----|----|
|STATE_DRAGGING|1|ボトムシートをつかんで移動開始時|
|STATE_SETTLING|2|STATE_EXPANDED、STATE_COLLAPSEDへの遷移中|
|STATE_EXPANDED|3|全表示中|
|STATE_COLLAPSED|4|縮小化（peekHeightで指定した高さ）での表示中|
|STATE_HIDDEN|5|ボトムシートが非表示中|

他にもたくさんあるようですが、確認できたのはここまでです。
追加で調べられれば追記します。

最後に
===
Android Support Libraryは非推奨となっており、[公式](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior)のドキュメントもAndroidXとなっています。

以下にAndroid Support LibraryからAndroidXへの移行方法も記載しています。
[AndroidXへの移行](https://qiita.com/kurramkurram/items/1ef7ca56662358ba151c)

ソースは[こちら](https://github.com/kurramkurram/LayoutBehavior)です。

参考文献
===
[BottomSheetBehaviorを使う](https://qiita.com/napplecomputer/items/5b3d1225533a59488ac3)
- 基本的にこちら参考させていただきました。
[公式](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior)
- AndroidX版です。Android Support Libraryは非推奨となっています。