キー フレーム アニメーションとイージング関数のアニメーション

線形キー フレーム アニメーション、KeySpline 値を設定したキー フレーム アニメーション、イージング関数は、ほとんど同じシナリオを実現できる 3 種類の手法です。そのシナリオとは、開始状態から終了状態までの間に非線形のアニメーション動作を使う、やや複雑なストーリーボードに設定されたアニメーションの作成です。

前提条件

トピック「ストーリーボードに設定されたアニメーション」を読んでいること。 このトピックは、「ストーリーボードに設定されたアニメーション」で説明したアニメーションの概念を基に作成されています。その内容はここでは触れません。 具体的には、「ストーリーボードに設定されたアニメーション」では、アニメーションのターゲットを設定する方法、リソースとしてのストーリーボード、DurationFillBehavior などの Timeline プロパティ値について紹介しています。

キー フレーム アニメーションを使ったアニメーション化

キー フレーム アニメーションでは、アニメーション タイムラインに沿ってポイントに到達する複数のターゲット値を使うことができます。 つまり、キー フレームごとに異なる中間値も指定でき、到達した最後のキー フレームが最終的なアニメーション値になります。 複数の値を指定してアニメーション化を行うことで、より複雑なアニメーションを実現できます。 キー フレーム アニメーションでは、アニメーションの種類ごとに異なる KeyFrame サブクラスとして実装される、異なる補間ロジックを使うこともできます。 具体的には、各種類のキー フレーム アニメーションには、キー フレームを指定するための KeyFrame クラスのバリエーションが 4 つ (DiscreteLinearSplineEasing) あります。 たとえば、Double をターゲットとし、キー フレームを使うアニメーションを指定するには、DiscreteDoubleKeyFrameLinearDoubleKeyFrameSplineDoubleKeyFrameEasingDoubleKeyFrame でキー フレームを宣言できます。 単一の KeyFrames コレクションに含まれるこれらすべての種類を使って、新しいキー フレームに到達するたびに補間を変更できます。

補間の動作のために、各キー フレームはその KeyTime の時間に達するまで補間を制御します。 その時点で、その Value にも達します。 それ以上のキー フレームがある場合は、値はシーケンス内の次のキー フレームの開始値になります。

アニメーションの開始時に、KeyTime が "0:0:0" のキー フレームがない場合、開始値はプロパティのアニメーション化されていない値になります。 これは、From がない場合の From/To/By アニメーションの動作方法と似ています。

キー フレーム アニメーションの継続時間は、いずれかのキー フレームに設定されている最も大きい KeyTime 値と暗黙的に等しくなります。 必要に応じて Duration を明示的に設定することもできますが、独自のキー フレームの KeyTime よりも短くならないように注意してください。アニメーションが途中で途切れることになります。

Duration 以外にも、From/To/By アニメーションの場合と同様に、Timeline ベースのすべてのプロパティをキー フレーム アニメーションに設定できます。キー フレーム アニメーション クラスも Timeline から派生しているためです。 次のとおりです。

  • AutoReverse: 最後のキー フレームに達すると、フレームは最後から逆に繰り返されます。 アニメーションの明確な継続時間が 2 倍になります。
  • BeginTime: アニメーションの開始を遅らせます。 BeginTime に達するまで、フレーム内にある KeyTime 値のタイムラインはカウントを開始しないため、フレームがカットされる心配はありません。
  • FillBehavior: 最後のキー フレームに達したときの処理を制御します。 FillBehavior はどの中間キー フレームにも影響しません。
  • RepeatBehavior:
    • Forever に設定した場合、キー フレームとそのタイムラインが無限に繰り返されます。
    • 反復回数に設定した場合、タイムラインはその回数だけ繰り返されます。
    • Duration に設定した場合、その時間に達するまでタイムラインが繰り返されます。 このとき、キー フレーム シーケンスの途中でアニメーションが途切れる可能性があります (タイムラインの暗黙的な継続時間の整数ファクターではない場合)。
  • SpeedRatio (通常は使いません)

線形キー フレーム

線形キー フレームの場合は、フレームの KeyTime に達するまで、値の単純な線形補間が行われます。 この補間の動作は、トピック「ストーリーボードに設定されたアニメーション」で説明されている単純な From/To/By アニメーションに非常に類似しています。

キー フレーム アニメーションで線形キー フレームを使って四角形の描画の高さをスケーリングする方法を以下に示します。 この例で実行するアニメーションでは、四角形の高さが最初の 4 秒間は線形にやや増加し、その後、四角形が当初の高さの 2 倍になるまで急速に拡大します。

<StackPanel>
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimationUsingKeyFrames
              Storyboard.TargetName="myRectangle"
              Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <LinearDoubleKeyFrame Value="1" KeyTime="0:0:0"/>
                <LinearDoubleKeyFrame Value="1.2" KeyTime="0:0:4"/>
                <LinearDoubleKeyFrame Value="2" KeyTime="0:0:5"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </StackPanel.Resources>
</StackPanel>

離散キー フレーム

離散キー フレームでは、補間を一切使いません。 KeyTime に達すると、新しい Value が単純に適用されます。 アニメーション化される UI プロパティに応じて、"ジャンプ" するように見えるアニメーションになることがよくあります。 これが、望みどおりのきれいな動作であることを確認してください。 宣言するキー フレームの数を増やすことで明確なジャンプを最小限に抑えることができますが、スムーズなアニメーションが必要な場合は、線形キー フレームかスプライン キー フレームを使うことをお勧めします。

注意

離散キー フレームは、DoublePointColor 型ではない値を DiscreteObjectKeyFrame でアニメーション化するための唯一の手段です。 その詳しい内容については、このトピックの後半で説明します。

スプライン キー フレーム

スプライン キー フレームでは、値から値までの可変的な遷移を KeySpline プロパティの値に基づいて作成します。 このプロパティは、ベジエ曲線の 1 つ目と 2 つ目の制御点を指定し、アニメーションの加速度を表します。 基本的には、KeySpline は、時間に基づく関数の関係 (関数の時間グラフがそのベジエ曲線の図形となる) を定義するものです。 通常は、スペースまたはコンマで区切った 4 つの Double 値を持つ XAML の短縮形の属性文字列で KeySpline 値を指定します。 これらの値は、ベジエ曲線の 2 つの制御点に対応する "X,Y" のペアです。 "X" は時間、"Y" は値に対する関数修飾子です。 各値は、必ず 0 と 1 の間 (両端を含む) である必要があります。 KeySpline に対する制御点を変更しない場合、0,0 から 1,1 までの直線は、線形補間の時間に基づく関数を表したものです。 制御点によってその曲線の図形が変化するため、スプライン アニメーションの時間に基づく関数の動作も変化します。 これはグラフで視覚的に確かめることをお勧めします。 ブラウザーで Silverlight キー スプライン ビジュアライザーのサンプルを実行すると、制御点によって曲線がどのように変化するかや、制御点を KeySpline 値として使ったときのサンプル アニメーションの動作を調べることができます。

次の例は、アニメーションに適用される 3 種類のキー フレームを示しています。最後のキー フレームは、Double 値のキー スプライン アニメーションです (SplineDoubleKeyFrame)。 文字列 "0.6,0.0 0.9,0.00" が KeySpline に対して適用されていることに注目してください。 これにより、アニメーションが最初はゆっくり動作するものの、KeyTime に達する直前で急速に速度を増す曲線となります。

<Storyboard x:Name="myStoryboard">
    <!-- Animate the TranslateTransform's X property
        from 0 to 350, then 50,
        then 200 over 10 seconds. -->
    <DoubleAnimationUsingKeyFrames
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X"
        Duration="0:0:10" EnableDependentAnimation="True">

        <!-- Using a LinearDoubleKeyFrame, the rectangle moves 
            steadily from its starting position to 500 over 
            the first 3 seconds.  -->
        <LinearDoubleKeyFrame Value="500" KeyTime="0:0:3"/>

        <!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly 
            appears at 400 after the fourth second of the animation. -->
        <DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4"/>

        <!-- Using a SplineDoubleKeyFrame, the rectangle moves 
            back to its starting point. The
            animation starts out slowly at first and then speeds up. 
            This KeyFrame ends after the 6th second. -->
        <SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

イージング キー フレーム

イージング キー フレームは、補間が適用され、補間の時間に基づく関数が複数の定義済みの数式によって制御されるキー フレームです。 スプライン キー フレームでは、一部の種類のイージング関数とほぼ同じ結果を得ることができるものの、スプラインでは再現できない BackEase などのイージング関数もあります。

イージング関数をイージング キー フレームに適用するには、EasingFunction プロパティをそのキー フレームの XAML でプロパティ要素として設定します。 値として、いずれかの種類のイージング関数のオブジェクト要素を指定します。

この例では、DoubleAnimation に対して CubicEase を適用し、さらに BounceEase を連続するキー フレームとして適用して、跳ね返りの効果を作成します。

<Storyboard x:Name="myStoryboard">
    <DoubleAnimationUsingKeyFrames Duration="0:0:10"
        Storyboard.TargetProperty="Height"
        Storyboard.TargetName="myEllipse">

        <!-- This keyframe animates the ellipse up to the crest 
            where it slows down and stops. -->
        <EasingDoubleKeyFrame Value="-300" KeyTime="00:00:02">
            <EasingDoubleKeyFrame.EasingFunction>
                <CubicEase/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>

        <!-- This keyframe animates the ellipse back down and makes
            it bounce. -->
        <EasingDoubleKeyFrame Value="0" KeyTime="00:00:06">
            <EasingDoubleKeyFrame.EasingFunction>
                <BounceEase Bounces="5"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

これはイージング関数の一例に過ぎません。 詳しくは、次のセクションをご覧ください。

イージング関数

イージング関数を使うと、独自の数式をアニメーションに適用することができます。 数学演算は、2-D の座標系で実際の物理法則をシミュレートするアニメーションを作るうえで役立ちます。 たとえば、オブジェクトをリアルにバウンドさせたり、バネに乗っているように動作させたりすることができます。 キー フレームや From/To/By アニメーションを使って、類似した効果を表現することもできますが、膨大な作業が必要となり、完成したアニメーションも、数式を使った場合と比べると正確さに欠ける可能性があります。

イージング関数は 3 とおりの方法でアニメーションに適用できます。

一連のイージング関数を以下にまとめます。

  • BackEase: 指定されたパスのアニメーションを開始する直前に、逆の動きを与えます。
  • BounceEase: 跳ね返りの効果を作成します。
  • CircleEase: 円関数を使って加速と減速のアニメーションを作成します。
  • CubicEase: 数式 f(t) = t3 を使って加速と減速のアニメーションを作成します。
  • ElasticEase: 伸び縮みを繰り返して静止する、ばねに似たアニメーションを作成します。
  • ExponentialEase: 指数関数の数式を使って加速と減速のアニメーションを作成します。
  • PowerEase: 数式 f(t) = tp を使って加速と減速のアニメーションを作成します (p = Power プロパティ)。
  • QuadraticEase: 数式 f(t) = t2 を使って加速と減速のアニメーションを作成します。
  • QuarticEase: 数式 f(t) = t4 を使って加速と減速のアニメーションを作成します。
  • QuinticEase: 数式 f(t) = t5 を使って加速と減速のアニメーションを作成します。
  • SineEase: 正弦公式を使って加速と減速のアニメーションを作成します。

一部のイージング関数には固有のプロパティがあります。 たとえば、BounceEase には BouncesBounciness という 2 つのプロパティがあります。これらは、その特定の BounceEase の時間に基づく関数の動作を変更します。 CubicEase など、その他のイージング関数は、すべてのイージング関数に共通の EasingMode プロパティ以外にプロパティはなく、生成される時間に基づく関数の動作は常に同じです。

これらのイージング関数の一部は、プロパティを持つイージング関数でのプロパティの設定方法に応じて、重複する場合があります。 たとえば、QuadraticEase は、Power が 2 の PowerEase と完全に同じです。 CircleEase は、基本的には既定値の ExponentialEase です。

BackEase イージング関数は、キー フレームの From/To または値によって設定される通常の範囲外の値を変更できるため、特別な関数です。 通常の From/To 動作とは逆の方向に値を変更することでアニメーションを開始し、From に戻るか、値をもう一度開始してから、アニメーションを通常どおり実行します。

前の例で、キー フレーム アニメーションのイージング関数を宣言する方法を紹介しました。 次の例では、イージング関数を From/To/By アニメーションに適用します。

<StackPanel x:Name="LayoutRoot" Background="White">
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimation From="30" To="200" Duration="00:00:3" 
                Storyboard.TargetName="myRectangle" 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <DoubleAnimation.EasingFunction>
                    <BounceEase Bounces="2" EasingMode="EaseOut" 
                                Bounciness="2"/>
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
    </StackPanel.Resources>
    <Rectangle x:Name="myRectangle" Fill="Blue" Width="200" Height="30"/>
</StackPanel>

イージング関数が From/To/By アニメーションに適用されると、時間に基づく関数の特性 (アニメーションの Duration に基づいて値が From 値と To 値の間で補完されるしくみ) が変化します。 イージング関数を使わない場合は、線形補間になります。

ディスクリート オブジェクト値のアニメーション

DoublePoint、または Color 型ではないプロパティにアニメーション化された値を適用する唯一の方法として、ある種類のアニメーションについて以下に説明します。 それは、キー フレーム アニメーション ObjectAnimationUsingKeyFrames です。 Object 値を使ったアニメーション化は、フレーム間で値が補間される可能性がないため、これとは異なります。 フレームの KeyTime に達すると、アニメーション化された値はキー フレームの Value に指定された値にすぐに設定されます。 補間がないため、ObjectAnimationUsingKeyFrames キー フレーム コレクションで使うキー フレームは DiscreteObjectKeyFrame だけです。

プロパティ要素構文を使って DiscreteObjectKeyFrameValue が設定されることはよくあります。これは、設定を試みるオブジェクト値が、属性構文の Value を設定するための文字列として表現できない場合があるためです。 StaticResource などの参照を使う場合は、属性構文を利用できます。

既定のテンプレートで ObjectAnimationUsingKeyFrames が使われる状況として、テンプレート プロパティが Brush リソースを参照する場合が挙げられます。 このようなリソースは単なる Color 値ではなく SolidColorBrush オブジェクトであり、システム テーマとして定義されているリソース (ThemeDictionaries) を使います。 これらのリソースは、TextBlock.Foreground などの Brush 型の値に直接割り当てることができ、間接的なターゲット設定を使う必要はありません。 ただし、SolidColorBrushDoublePoint、または Color ではないため、リソースを使うには ObjectAnimationUsingKeyFrames を利用する必要があります。

<Style x:Key="TextButtonStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent">
                    <TextBlock x:Name="Text"
                        Text="{TemplateBinding Content}"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPointerOverForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
...
                       </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

列挙値を使うプロパティをアニメーション化するために、ObjectAnimationUsingKeyFrames を使うこともできます。 次に、Windows ランタイムの既定のテンプレートに含まれている名前付きスタイルの別の例を示します。 Visibility 列挙定数を列挙定数受け取る Visibility プロパティの設定方法に注目してください。 この場合は、属性構文を使って値を設定できます。 必要なのは、プロパティに "Collapsed" などの列挙値を設定するための列挙値からの非修飾定数名だけです。

<Style x:Key="BackButtonStyle" TargetType="Button">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Grid x:Name="RootGrid">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal"/>
...           <VisualState x:Name="Disabled">
                <Storyboard>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame Value="Collapsed" KeyTime="0"/>
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
...
          </VisualStateManager.VisualStateGroups>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

ObjectAnimationUsingKeyFrames フレーム セットに対して、複数の DiscreteObjectKeyFrame を使うことができます。 この方法は、複数のオブジェクト値が役立つサンプル シナリオで、Image.Source の値をアニメーション化して "スライド ショー" アニメーションを作成する際に検討することをお勧めします。