アニメーションをカスタマイズする

アニメーション API の多くは、動作をカスタマイズするためのパラメータを受け入れます。

AnimationSpec パラメータでアニメーションをカスタマイズする

ほとんどのアニメーション API では、オプションの AnimationSpec パラメータでアニメーションの仕様をカスタマイズできます。

val alpha: Float by animateFloatAsState(
    targetValue = if (enabled) 1f else 0.5f,
    // Configure the animation duration and easing.
    animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing),
    label = "alpha"
)

各種アニメーションの作成に対応した、さまざまなタイプの AnimationSpec があります。

spring を使用して物理ベースのアニメーションを作成する

spring は、開始値と終了値の間で物理学ベースのアニメーションを作成します。dampingRatiostiffness の 2 つのパラメータを受け取ります。

dampingRatio は、ばねの弾性を定義します。デフォルト値は Spring.DampingRatioNoBouncy です。

図 1. ばねの減衰率を変更する。

stiffness は、終了値までのばねの移動速度を定義します。デフォルト値は Spring.StiffnessMedium です。

図 2. ばねの剛性を変更する

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = spring(
        dampingRatio = Spring.DampingRatioHighBouncy,
        stiffness = Spring.StiffnessMedium
    ),
    label = "spring spec"
)

継続時間ベースの AnimationSpec 型と比べて、spring は中断をより適切に処理できます。これは、spring の場合、アニメーション中にターゲット値が変更されたときに速度の継続性が保証されるためです。spring は、animate*AsStateupdateTransition など、多くのアニメーション API によってデフォルトの AnimationSpec として使用されます。

たとえば、ユーザーのタップによって駆動される次のアニメーションに spring 構成を適用した場合、アニメーションの進行中に中断すると、tween を使用すると spring を使用する場合ほどスムーズに応答しないことがわかります。

図 3. アニメーションの tweenspring の仕様を設定して中断する。

tween でイージング カーブを使用して開始値と終了値の間をアニメーション化する

tween は、イージング カーブを使用して、指定された durationMillis の開始値と終了値の間をアニメーション化します。tween は、2 つの値のを示す between の略語です。

delayMillis を指定して、アニメーションの開始を延期することもできます。

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = tween(
        durationMillis = 300,
        delayMillis = 50,
        easing = LinearOutSlowInEasing
    ),
    label = "tween delay"
)

詳しくは、イージングをご覧ください。

keyframes を使用して、特定のタイミングで特定の値にアニメーション化する

keyframes は、アニメーションの持続時間内の異なるタイムスタンプで指定されたスナップショット値に基づいてアニメーション化します。アニメーション値は、常に 2 つのキーフレーム値の間で補間されます。これらのキーフレームごとに、イージングを指定して補間曲線を設定できます。

0 ms と持続時間の値の指定はオプションです。これらの値を指定しない場合は、デフォルトでアニメーションの開始値と終了値が設定されます。

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = keyframes {
        durationMillis = 375
        0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms
        0.2f at 15 using FastOutLinearInEasing // for 15-75 ms
        0.4f at 75 // ms
        0.4f at 225 // ms
    },
    label = "keyframe"
)

repeatable でアニメーションを繰り返す

repeatable は、指定された繰り返し回数に達するまで、持続時間ベースのアニメーション(tweenkeyframes など)を繰り返します。repeatMode パラメータを渡すと、アニメーションを繰り返す際に、最初から(RepeatMode.Restart)開始するか、最後から(RepeatMode.Reverse)開始するかを指定できます。

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = repeatable(
        iterations = 3,
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "repeatable spec"
)

infiniteRepeatable を使用してアニメーションを無限に繰り返す

infiniteRepeatablerepeatable に似ていますが、繰り返し回数が無限である点が異なります。

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = infiniteRepeatable(
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "infinite repeatable"
)

ComposeTestRule を使用したテストでは、infiniteRepeatable を使用したアニメーションは実行されません。各アニメーション値の初期値を使用してコンポーネントがレンダリングされます。

snap で終了値にすぐにスナップ

snap は、値をすぐに終了値に切り替える特別な AnimationSpec です。delayMillis を指定して、アニメーションの開始を遅らせることができます。

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = snap(delayMillis = 50),
    label = "snap spec"
)

カスタム イージング関数を設定する

持続時間ベースの AnimationSpec オペレーション(tweenkeyframes など)では、Easing を使用してアニメーションの割合を調整します。これにより、アニメーション化する値の速度を変えながら動かすことができます。割合は、0(開始)から 1.0(終了)までの値で、アニメーションの現在の位置を示します。

Easing とは、実際には 0~1.0 の小数値を受け取り、浮動小数点数を返す関数です。戻り値は、オーバーシュートまたはアンダーシュートを表すために境界外となる場合もあります。カスタム Easing は、次のようなコードで作成できます。

val CustomEasing = Easing { fraction -> fraction * fraction }

@Composable
fun EasingUsage() {
    val value by animateFloatAsState(
        targetValue = 1f,
        animationSpec = tween(
            durationMillis = 300,
            easing = CustomEasing
        ),
        label = "custom easing"
    )
    // ……
}

Compose には、ほとんどのユースケースに対応できる組み込みの Easing 関数がいくつか用意されています。シナリオに応じた Easing の使用について詳しくは、スピード - マテリアル デザインをご覧ください。

  • FastOutSlowInEasing
  • LinearOutSlowInEasing
  • FastOutLinearEasing
  • LinearEasing
  • CubicBezierEasing
  • 詳細を見る

AnimationVector との間で変換を行い、カスタムデータ型をアニメーション化する

ほとんどの Compose アニメーション API は、デフォルトでアニメーション値として FloatColorDp などの基本的なデータ型をサポートしていますが、カスタムのデータ型など、他のデータ型のアニメーション化が必要な場合もあります。アニメーション中、アニメーション化する値は AnimationVector として表されます。値は、対応する TwoWayConverter によって AnimationVector に変換されます(逆も同様です)。これにより、コア アニメーション システムが値を均一に処理できるようになります。たとえば、Int は、単一の浮動小数点値を保持する AnimationVector1D として表されます。IntTwoWayConverter は次のようになります。

val IntToVector: TwoWayConverter<Int, AnimationVector1D> =
    TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })

Color は基本的に 4 つの値(赤、緑、青、アルファ)のセットであるため、Color は 4 つの浮動小数点値を保持する AnimationVector4D に変換されます。このように、アニメーションで使用されるデータ型はすべて、次元数に応じて AnimationVector1DAnimationVector2DAnimationVector3DAnimationVector4D のいずれかに変換されます。これにより、オブジェクトの異なるコンポーネントを別々にアニメーション化し、それぞれの速度をトラッキングすることができます。基本的なデータ型の組み込みコンバータには、Color.VectorConverterDp.VectorConverter などのコンバータを使用してアクセスできます。

新しいデータ型のサポートをアニメーション化する値として追加する場合は、独自の TwoWayConverter を作成して API に指定できます。たとえば、次のように animateValueAsState を使用してカスタムのデータ型をアニメーション化できます。

data class MySize(val width: Dp, val height: Dp)

@Composable
fun MyAnimation(targetSize: MySize) {
    val animSize: MySize by animateValueAsState(
        targetSize,
        TwoWayConverter(
            convertToVector = { size: MySize ->
                // Extract a float value from each of the `Dp` fields.
                AnimationVector2D(size.width.value, size.height.value)
            },
            convertFromVector = { vector: AnimationVector2D ->
                MySize(vector.v1.dp, vector.v2.dp)
            }
        ),
        label = "size"
    )
}

次のリストに、組み込みの VectorConverter を示します。