0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Android]WRAP_CONTENTが指定されたViewのアニメーション

Last updated at Posted at 2022-11-09

やりたいこと

あるViewは高さにはWRAP_CONTENTが指定されていて
RelativeLayoutでそのViewの上下に制約がある場合に、その制約を維持しつつViewの高さを変えたり元に戻したりするアニメーションがしたい。
ここで問題になるのはWRAP_CONTENTなので高さを戻したい時に具体的な高さの値が分からないのでValueAnimatorで目的の値の指定に困るということ。

画面のイメージ
このImageViewに上下に挟まれたTextViewを縦方向縮めたり広げたりしてみます
Screenshot_20221108-144327_WrapContentAnimationSample.jpg

実装

レイアウト

activity_main.xml
<?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">

    <ImageView
        android:id="@+id/image_view1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:src="@drawable/ic_launcher_background"/>

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!\nHello World!"
        app:layout_constraintTop_toBottomOf="@+id/image_view1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>

    <ImageView
        android:id="@+id/image_view2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_view"
        android:src="@drawable/ic_launcher_background"/>

    <Button
        android:id="@+id/toggle_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:text="アニメ"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

縮小する

MainActivity.kt
private fun collapse() {
    val actualHeight = binding.textView.height
    ValueAnimator.ofInt(actualHeight, 1).apply {
        duration = 200
        addUpdateListener { animator ->
            val newValue = animator.animatedValue as Int
            val layoutParams = binding.textView.layoutParams.apply {
                height = newValue
            }
            binding.textView.layoutParams = layoutParams
        }
        doOnEnd {
            binding.textView.visibility = View.INVISIBLE
        }
        start()
    }
}

縮小するにはまず実際に表示されているViewの高さが必要で、これはViewのheightプロパティから取得できます。ではLayoutParams.WRAP_CONTENT(-2)はどこに入っているかというとView.layoutParams.heightになります。
アニメーション進行中はViewのlayoutParamsのheightを更新していきます。
この時、binding.textView.layoutParams.heightに直接newValueを代入してもViewは更新されません。更新したlayoutParamsを改めてbinding.textView.layoutParamsに代入することでViewが更新されます。

拡大する

MainActivity.kt
private fun expand() {
    // [POINT]WRAP_CONTENTを指定した時の高さを計算します。
    binding.textView.measure(WRAP_CONTENT, WRAP_CONTENT)
    val expectedHeight = binding.textView.measuredHeight
    ValueAnimator.ofInt(1, expectedHeight).apply {
        duration = 200
        addUpdateListener { animator ->
            val newValue = animator.animatedValue as Int
            val layoutParams = binding.textView.layoutParams.apply {
                height = newValue
            }
            binding.textView.layoutParams = layoutParams
        }
        doOnStart {
            binding.textView.visibility = View.VISIBLE
        }
        doOnEnd {
            val layoutParams = binding.textView.layoutParams.apply {
                height = WRAP_CONTENT
            }
            binding.textView.layoutParams = layoutParams
        }
        start()
    }
}

拡大するときは目的となる高さが必要になりますが、WRAP_CONTENTが指定されているため具体的な数値はわかりません。(縮小する時にメンバ変数に覚えておいても良いけど)
そこで、ViewのmeasureメソッドとmeasuredHeightプロパティを使ってWRAP_CONTENTが指定された時の具体的な数値を計算することができます。
アニメーション中は縮小の時と同じです。念のためアニメーションを終えたタイミングでWRAP_CONTENTに戻しておきます。

最終的にはアニメボタンを押すとTextViewがアニメーションしながら消えたり表示されたりします。

Screenshot_20221108-144327_WrapContentAnimationSample.jpg Screenshot_20221108-144333_WrapContentAnimationSample.jpg

ソースコード

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?