[Kotlin]スクロールするとヘッダーに収納されるTextViewを力技で作成してみた。[Android]

#はじめに
スクロールするとヘッダーに収納されるマーキーのタイトルを作りたくて始めた結果、力技で実装することにしました。


__やりたいこと__
![無題94.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/de486da4-6316-820b-6503-3cb2a36ac2b8.png)
スクロールすると左画像の[ハチワレ女王]が右画像のようにヘッダーに収納される

<br>
__力技に至った経緯__
1.&ensp;CollapsingToolbarLayout + Toolbarで実装しよう!
&emsp;<font color="Silver">> Toolbarにマーキーがない</font>
2.&ensp;マーキーするToolbarをカスタムビューで作ろう!
&emsp;<font color="Silver">> リフレクションでTextView引っこ抜いてマーキーする設定にしたけどマーキーしない</font>

<font color="Red">↓　とりあえず実装させたい! 力技でやろう!</font>

3.&ensp;collapseModeをpinにしたTextViewで作ろう!
&emsp;<font color="Silver">> スクロール中の動作が気に入らない</font>
4.&ensp;AppBarLayout.OnOffsetChangedListenerを使ってpaddingの高さを調整することで再現しよう!
&emsp;<font color="Silver">>できた!!!</font>


この記事では3と4について記述します。


#CollapsingToolbarLayout + TextView
CollapsingToolbarLayoutの中にTextViewを配置し、collapseModeをpinにして再現させる。

```xml:layout_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/background">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/clear">
            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/collapsing"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:minHeight="50dp"
                android:background="@color/clear"
                app:collapsedTitleGravity="center"
                app:collapsedTitleTextAppearance="@style/collapsedTitle"
                app:expandedTitleGravity="top|start"
                app:expandedTitleMarginTop="65dp"
                app:expandedTitleTextAppearance="@style/expandedTitle"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">
                <ImageView
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:scaleType="centerCrop"
                    android:layout_marginTop="70dp"
                    android:layout_gravity="center_horizontal"
                    android:src="@drawable/cat"/>
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="320dp"
                    android:layout_marginHorizontal="30dp"
                    android:singleLine="false"
                    android:gravity="center"
                    android:textSize="15sp"
                    android:text="@string/expo"/>
                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:background="@color/white"
                    app:layout_collapseMode="pin">
                    <com.google.android.material.button.MaterialButton
                        android:id="@+id/back_button"
                        style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
                        android:layout_width="30dp"
                        android:layout_height="match_parent"
                        app:iconGravity="start"
                        app:icon="@drawable/ic_back"
                        app:iconTint="@color/black" />
                </FrameLayout>
                <com.example.MarqueeTextView
                    android:id="@+id/name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:minHeight="50dp"
                    android:layout_marginTop="270dp"
                    android:paddingHorizontal="50dp"
                    android:gravity="center"
                    android:textSize="20sp"
                    android:text="ハチワレ女王"
                    app:layout_collapseMode="pin"/>
                <TextView
                    android:id="@+id/screen_title"
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:layout_marginHorizontal="50dp"
                    android:gravity="center"
                    android:text="お猫様と配下一覧"
                    app:layout_collapseMode="parallax"/>
            </com.google.android.material.appbar.CollapsingToolbarLayout>
        </com.google.android.material.appbar.AppBarLayout>
        
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
    
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
```

CollapsingToolbarLayout内にタイトルより下の位置にもtextが配置されているのでスクロール中文字が被ってしまった。
また、このデザインでは問題なかったが、左右の移動もできないためデフォルト位置とヘッダーの時の位置がずれる場合に使用できなかった。

![qiita1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/a19cb9f6-2a34-5ca7-1160-78ccfa3b13fb.gif)

#AppBarLayout.OnOffsetChangedListener + padding制御
AppBarLayoutの高さの変化を検知してくれるAppBarLayout.OnOffsetChangedListenerを使用し高さに応じてpaddingを調整する。

レイアウトは変更部分のみ記載します。

```xml:layout_main.xml
             <!--   old: android:layout_marginTop="270dp"
                    new: android:paddingTop="280dp"         -->
                <com.example.MarqueeTextView
                    android:id="@+id/name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:minHeight="50dp"
                    android:paddingTop="280dp"
                    android:paddingHorizontal="50dp"
                    android:gravity="center"
                    android:textSize="20sp"
                    android:text="ハチワレ女王"
                    app:layout_collapseMode="pin"/>
```

```kotlin:MainFragment.kt
class MainFragment : Fragment() {
    private lateinit var listener: AppBarLayout.OnOffsetChangedListener
    private lateinit var binding: FragmentFirstBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return FragmentFirstBinding.inflate(inflater, container, false).apply {
            val strList = mutableListOf("ヒト1: お気に入り", "ヒト2: ご飯係", "ヒト3: おやつ係", "ヒト4: ブラッシング係",
                "ヒト5: 爪を切る不届きもの", "ヒト6: お気に入りその２", "ヒト7: ご飯係その２", "ヒト8: おやつ係その２")
            list.adapter = ListAdapter(strList)
            list.layoutManager = LinearLayoutManager(context)

            //paddingの制御
            val paddingHorizontal = resources.getDimensionPixelSize(R.dimen.padding_horizontal) //50dp
            val defaultPaddingTop = resources.getDimensionPixelSize(R.dimen.padding_top)        //280dp
            listener = AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
                val paddingTop = if (defaultPaddingTop + verticalOffset > 0) defaultPaddingTop + verticalOffset
                else 0
                name.setPadding(paddingHorizontal, paddingTop, paddingHorizontal, 0)
            }
            appbarLayout.addOnOffsetChangedListener(listener)

        }.root
    }

    override fun onPause() {
        super.onPause()
        binding.appbarLayout.removeOnOffsetChangedListener(listener)
    }
}
```

![qiita2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/b42ee533-2642-89e9-4290-4758850058fe.gif)

AppBarLayout.OnOffsetChangedListenerのverticalOffsetはデフォルトの状態が0で上方向にスクロールするとマイナス値になる。
あらかじめ設定したデフォルトの値にverticalOffsetを加算することでスクロールと同じようにタイトルが動くようになる。

![qiita3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/c71d378d-fb4a-b577-1136-5faf37e91db5.gif)
マーキーするようにしたTextViewのCustomViewを使っているのでもちろんマーキーもする。
<br>

#最後に
今回は動きを力技で実装することができましたが、マーキーするToolbarも含めもっと上手く実装できる方法があったのではないかと思います。
自分の知識の少なさを再認識しもっと勉強しようと思えた良い機会になりました。
マーキーするToolbarについてはしっかり動作するものが作れるまで頑張ろうと思います。