Toolbarのサブタイトルをアニメーションする (CollapsingToolbarLayout subtitle)
2021/09/15
CollapsingToolbarLayoutを使ってモダンなUIにしたい時でも、殆どの方は単体のToolbarも併用していると思います。しかし、タイトルをアニメーションさせたい時はCollapsingToolbarLayoutのタイトルを使わないと出来ませんし、サブタイトルに対応していません。
そこで、タイトルとサブタイトルはToolbarに任せたままで、スライドアニメーションさせてみます。
スクロールを検知してタイトルを拡大させるBehaviorを作る
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.example.myapplication.R
import com.google.android.material.appbar.AppBarLayout
import kotlin.math.abs
import kotlin.math.round
class CollapsingTitleBehavior(context: Context, attrs: AttributeSet): CoordinatorLayout.Behavior<ViewGroup>() {
private var collapsedTitleSize = 0f
private var collapsedSubtitleSize = 0f
override fun layoutDependsOn(parent: CoordinatorLayout, child: ViewGroup, dependency: View): Boolean {
return dependency is AppBarLayout
}
override fun onDependentViewChanged(parent: CoordinatorLayout, child: ViewGroup, dependency: View): Boolean {
dependency as AppBarLayout
val toolbar: Toolbar = dependency.findViewById(R.id.toolbar)
val titleTextView = toolbar.getChildAt(0) as? TextView
val subtitleTextView = toolbar.getChildAt(1) as? TextView
if (collapsedTitleSize == 0f) {
collapsedTitleSize = (titleTextView?.textSize ?: 0f) / toolbar.resources.displayMetrics.density
}
if (collapsedSubtitleSize == 0f) {
collapsedSubtitleSize = (subtitleTextView?.textSize ?: 0f) / toolbar.resources.displayMetrics.density
}
val scale = {
// 1.0 ~ 1.4
val p = 1f + 0.4f * (1f - abs(dependency.y) / dependency.totalScrollRange)
// Smooths the animation
round(p * 100f) / 100f
}()
titleTextView?.textSize = collapsedTitleSize * scale
subtitleTextView?.textSize = collapsedSubtitleSize * scale
return true
}
}
activity_main.xml
CoordinatorLayout直下に空のレイアウトを配置して先ほどのBehaviorを仕込むだけ。
<?xml version="1.0" encoding="utf-8"?>
<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"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<!-- This will not be displayed -->
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior="com.example.myapplication.CollapsingTitleBehavior" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:expanded="false">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="200dp"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:statusBarScrim="?attr/colorPrimary"
app:titleEnabled="false">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="Logo"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
app:srcCompat="@drawable/ic_launcher_foreground" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_collapseMode="pin"
app:subtitle="サブタイトル"
app:subtitleTextColor="@android:color/white"
app:title="メインタイトル"
app:titleTextColor="@android:color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
拡大アニメーションがちょっとかくつきます。^^;;;
今回は拡大だけでしたが、文字色をレイアウト側で設定できるように改良すると実用性も上がると思います。