WPF动画

目录

引言

[1、"From/To/By" 动画](#1、“From/To/By” 动画)

1.1、示例

2、关键帧动画

[2.1、 示例](#2.1、 示例)

2.2、时间百分比

2.3、时间等分Uniform

2.4、匀速变化Paced

3、缓动函数

3.1、自定义缓动函数

4、路径动画

[4.1、WPF 提供以下路径动画类](#4.1、WPF 提供以下路径动画类)

4.2、路径输入

5、动画触发/开始

6、其他指导

6.1、加速减速

6.2、重复循环中累加动画值

6.3、将动画终值设为下次的起始值

6.4、如何添加动画

6.4.1、控件的EventTrigger

6.4.2、控件模板ControlTemplate:EventTrigger、Trigger

6.4.3、样式Style:EventTrigger

6.5、动画终值保持并触发事件

6.6、不同起始时间的动画管理

6.7、动画的过渡方式


引言

Windows Presentation Foundation (WPF) 提供了一组强大的图形和布局功能,使用户能够创建引起注意的用户界面和有吸引力的文档。 动画不仅可以使引起注意的用户界面更加引人注目,还可以使其更加便于使用。 只需对背景色进行动画处理或应用经过动画处理的 Transform,即可创造出生动的屏幕过渡效果或提供有帮助的视觉提示。

动画类型包括 "From/To/By" 动画、关键帧动画、路径动画和抽象类 AnimationBase,动画都是继承自 Timeline 类的时间线,具有 Duration、AutoReverse 和 RepeatBehavior 等计时属性。

动画结束后,FillBehavior (默认HoldEnd)属性决定了时间线结束时的行为方式,默认情况下会保持最终输出值(如果不希望保持,设置为Stop)。在代码中可以通过特定方法重新获得动画属性的控制权。

1、"From/To/By" 动画

From/To/By 动画是一种 AnimationTimeline 类型,可在起始值和终止值之间创建转换。 完成转换所需的时间取决于该动画的 Duration。WPF 提供以下 From/To/By 动画类。

属性类型 对应的 From/To/By 动画类
Byte ByteAnimation
Color ColorAnimation
Decimal DecimalAnimation
Double DoubleAnimation
Int16 Int16Animation
Int32 Int32Animation
Int64 Int64Animation
Point PointAnimation
Quaternion QuaternionAnimation
Rect RectAnimation
Rotation3D Rotation3DAnimation
Single SingleAnimation
Size SizeAnimation
Thickness ThicknessAnimation
Vector3D Vector3DAnimation
Vector VectorAnimation
  • 起始值From

    要显式指定动画起始值时,请使用 From 属性。 可以单独使用 From 属性,也可以与 ToBy 属性结合使用。 如果仅指定 From 属性,则动画从该值转换到动画处理属性的基值。

  • 终止值To

    若要指定动画的终止值,请设置其 To 属性。 如果单独使用 To 属性,则动画从要进行动画处理的属性中获取其起始值,或者从应用到相同属性的另一个动画的输出中获取其起始值。 可以将 To 属性与 From 属性一起使用,以显式指定动画的起始值和终止值。

  • 偏移值By

    使用 By 属性,可以为动画指定偏移,而不是显式的起始或终止值 。 动画的 By 属性指定动画在其持续时间内更改某个值的程度。 可以单独使用 By 属性,或者与 From 属性结合使用。 如果仅指定 By 属性,动画会将偏移值添加到属性的基值或另一个动画的输出。

1.1、示例

这里使用偏移值:By="10",该值会直接与属性值相加得到最终值(即To值),动画结束行为设置为Stop(即不保持动画终止结果)

cs 复制代码
<Window.Resources>
    <Storyboard
        x:Key="story1"
        FillBehavior="Stop"
        Storyboard.TargetName="label"
        Storyboard.TargetProperty="FontSize">
        <DoubleAnimation By="10" Duration="0:0:0.5" />
    </Storyboard>
</Window.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <Label Name="label" Content="Label">
        <Label.Triggers>
            <EventTrigger RoutedEvent="MouseEnter">
                <BeginStoryboard Storyboard="{StaticResource story1}" />
            </EventTrigger>
        </Label.Triggers>
    </Label>
</Grid>

A: 稍微更改一下:如果我们设置为保持动画结果(即默认值)会怎样?删除FillBehavior属性设置。

此时会越来越大,可以理解为动画结果已经将原来的属性值进行了更改。

**B:**再更改一下:鼠标进入放大,鼠标离开还原。还是使用By偏移进行设置,看似没问题

cs 复制代码
 <Window.Resources>
     <Storyboard
         x:Key="story1"
         Storyboard.TargetName="label"
         Storyboard.TargetProperty="FontSize">
         <DoubleAnimation By="10" Duration="0:0:0.5" />
     </Storyboard>
     <Storyboard
         x:Key="story2"
         Storyboard.TargetName="label"
         Storyboard.TargetProperty="FontSize">
         <DoubleAnimation By="-10" Duration="0:0:0.5" />
     </Storyboard>
 </Window.Resources>
 <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
     <Label Name="label" Content="Label">
         <Label.Triggers>
             <EventTrigger RoutedEvent="MouseEnter">
                 <BeginStoryboard Storyboard="{StaticResource story1}" />
             </EventTrigger>
             <EventTrigger RoutedEvent="MouseLeave">
                 <BeginStoryboard Storyboard="{StaticResource story2}" />
             </EventTrigger>
         </Label.Triggers>
     </Label>
 </Grid>

上面说到By会直接追加到属性的初始值上,当我们触发频率超过动画时长时,会出现叠加效果。

**C:**如果想要确定的结果,我们需要对By偏移值追加一个初始值From,也即确定了终值To。

cs 复制代码
<Window.Resources>
    <Storyboard
        x:Key="story1"
        Storyboard.TargetName="label"
        Storyboard.TargetProperty="FontSize">
        <DoubleAnimation
            By="10"
            From="20"
            Duration="0:0:0.5" />
    </Storyboard>
    <Storyboard
        x:Key="story2"
        Storyboard.TargetName="label"
        Storyboard.TargetProperty="FontSize">
        <DoubleAnimation
            By="-10"
            From="30"
            Duration="0:0:0.5" />
    </Storyboard>
</Window.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <Label Name="label" Content="Label">
        <Label.Triggers>
            <EventTrigger RoutedEvent="MouseEnter">
                <BeginStoryboard Storyboard="{StaticResource story1}" />
            </EventTrigger>
            <EventTrigger RoutedEvent="MouseLeave">
                <BeginStoryboard Storyboard="{StaticResource story2}" />
            </EventTrigger>
        </Label.Triggers>
    </Label>
</Grid>

**D:**这里我们确定了初始值,通过计算得出终值,动画始终会从初始值开始,当动画未结束时触发另外动画,就会出现突变现象。如果想要避免,可以不设定初始值,只设定重点目标To

cs 复制代码
<Storyboard
    x:Key="story1"
    Storyboard.TargetName="label"
    Storyboard.TargetProperty="FontSize">
    <DoubleAnimation To="30" Duration="0:0:0.5" />
</Storyboard>
<Storyboard
    x:Key="story2"
    Storyboard.TargetName="label"
    Storyboard.TargetProperty="FontSize">
    <DoubleAnimation To="20" Duration="0:0:0.5" />
</Storyboard>

2、关键帧动画

与 From/To/By 动画类似,关键帧动画对目标属性的值进行动画处理。 它通过其 Duration 在目标值之间创建过渡。 但是,From/To/By 动画可以在两个值之间创建过渡,而单个关键帧动画可以在任意数量的目标值之间创建过渡。 不同于 From/To/By 动画,关键帧动画没有设置其目标值所需的 From、To 或 By 属性。 关键帧动画的目标值使用关键帧对象进行描述,因此称作"关键帧动画"。 若要指定动画的目标值,请创建关键帧对象并将其添加到动画的 KeyFrames 集合。 动画运行时,将在指定的帧之间过渡。

某些关键帧方法除支持多个目标值外,甚至还支持多个内插方法。 动画的内插方法定义了从一个值过渡到下一个值的方式。 有三种内插类型:离散、线性和曲线

属性类型 对应的 From/To/By 动画类 支持的内插方法
Boolean BooleanAnimationUsingKeyFrames 离散
Byte ByteAnimationUsingKeyFrames 离散、线性、曲线
Color ColorAnimationUsingKeyFrames 离散、线性、曲线
Decimal DecimalAnimationUsingKeyFrames 离散、线性、曲线
Double DoubleAnimationUsingKeyFrames 离散、线性、曲线
Int16 Int16AnimationUsingKeyFrames 离散、线性、曲线
Int32 Int32AnimationUsingKeyFrames 离散、线性、曲线
Int64 Int64AnimationUsingKeyFrames 离散、线性、曲线
Matrix MatrixAnimationUsingKeyFrames 离散
Object ObjectAnimationUsingKeyFrames 离散
Point PointAnimationUsingKeyFrames 离散、线性、曲线
Quaternion QuaternionAnimationUsingKeyFrames 离散、线性、曲线
Rect RectAnimationUsingKeyFrames 离散、线性、曲线
Rotation3D Rotation3DAnimationUsingKeyFrames 离散、线性、曲线
Single SingleAnimationUsingKeyFrames 离散、线性、曲线
String StringAnimationUsingKeyFrames 离散
Size SizeAnimationUsingKeyFrames 离散、线性、曲线
Thickness ThicknessAnimationUsingKeyFrames 离散、线性、曲线
Vector3D Vector3DAnimationUsingKeyFrames 离散、线性、曲线
Vector VectorAnimationUsingKeyFrames 离散、线性、曲线

插值方法:

cs 复制代码
离散
<DiscreteDoubleKeyFrame Value="500" KeyTime="0:0:7" />
线性
<LinearDoubleKeyFrame Value="200" KeyTime="0:0:10" />
曲线
<SplineDoubleKeyFrame Value="350" KeyTime="0:0:15"  KeySpline="0.0,0.0 1.0,0.0"/>

2.1、 示例

**A:**鼠标进入右移,鼠标离开还原关键帧动画

cs 复制代码
<Window.Resources>
    <Storyboard
        x:Key="story1"
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X">
        <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
            <LinearDoubleKeyFrame KeyTime="0:0:0" Value="0" />
            <LinearDoubleKeyFrame KeyTime="0:0:0.25" Value="10" />
            <LinearDoubleKeyFrame KeyTime="0:0:0.5" Value="20" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard
        x:Key="story2"
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X">
        <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
            <LinearDoubleKeyFrame KeyTime="0:0:0" Value="20" />
            <LinearDoubleKeyFrame KeyTime="0:0:0.25" Value="10" />
            <LinearDoubleKeyFrame KeyTime="0:0:0.5" Value="0" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <Label Name="label" Content="Label">
        <Label.RenderTransform>
            <TranslateTransform x:Name="MyAnimatedTranslateTransform" X="0" Y="0" />
        </Label.RenderTransform>
        <Label.Triggers>
            <EventTrigger RoutedEvent="MouseEnter">
                <BeginStoryboard Storyboard="{StaticResource story1}" />
            </EventTrigger>
            <EventTrigger RoutedEvent="MouseLeave">
                <BeginStoryboard Storyboard="{StaticResource story2}" />
            </EventTrigger>
        </Label.Triggers>
    </Label>
</Grid>

2.2、时间百分比

KeyTime不仅可以直接写时间,还可以写百分比。

cs 复制代码
<Storyboard
    x:Key="story1"
    Storyboard.TargetName="MyAnimatedTranslateTransform"
    Storyboard.TargetProperty="X">
    <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="0" Value="0" />
        <LinearDoubleKeyFrame KeyTime="50%" Value="10" />
        <LinearDoubleKeyFrame KeyTime="100%" Value="20" />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard
    x:Key="story2"
    Storyboard.TargetName="MyAnimatedTranslateTransform"
    Storyboard.TargetProperty="X">
    <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="0" Value="20" />
        <LinearDoubleKeyFrame KeyTime="50%" Value="10" />
        <LinearDoubleKeyFrame KeyTime="100%" Value="0" />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

2.3、时间等分Uniform

如果希望每个关键帧的持续时间都相同,应使用 Uniform 计时。Uniform 关键时间按关键帧的数量平均分配可用时间,以确定每个关键帧的结束时间。

cs 复制代码
​
<Storyboard
    x:Key="story1"
    Storyboard.TargetName="MyAnimatedTranslateTransform"
    Storyboard.TargetProperty="X">
    <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="Uniform" Value="0" />
        <LinearDoubleKeyFrame KeyTime="Uniform" Value="10" />
        <LinearDoubleKeyFrame KeyTime="Uniform" Value="20" />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard
    x:Key="story2"
    Storyboard.TargetName="MyAnimatedTranslateTransform"
    Storyboard.TargetProperty="X">
    <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="Uniform" Value="20" />
        <LinearDoubleKeyFrame KeyTime="Uniform" Value="10" />
        <LinearDoubleKeyFrame KeyTime="Uniform" Value="0" />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

2.4、匀速变化Paced

如果希望以固定速率进行动画处理,应使用 Paced 计时。Paced 关键时间根据每一关键帧的长度来分配可用时间,以确定每帧的持续时间。 这样,动画的速度或速率将保持不变。

cs 复制代码
<Storyboard
    x:Key="story1"
    Storyboard.TargetName="MyAnimatedTranslateTransform"
    Storyboard.TargetProperty="X">
    <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="Paced" Value="0" />
        <LinearDoubleKeyFrame KeyTime="Paced" Value="10" />
        <LinearDoubleKeyFrame KeyTime="Paced" Value="20" />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard
    x:Key="story2"
    Storyboard.TargetName="MyAnimatedTranslateTransform"
    Storyboard.TargetProperty="X">
    <DoubleAnimationUsingKeyFrames Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="Paced" Value="20" />
        <LinearDoubleKeyFrame KeyTime="Paced" Value="10" />
        <LinearDoubleKeyFrame KeyTime="Paced" Value="0" />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

3、缓动函数

缓动函数允许将自定义的数学公式应用到动画。 例如,用户可能希望某个对象逼真地弹跳或表现出像在弹簧上一样 。 可使用关键帧 甚至From/To/By 动画来近似地实现这些效果,但它将需要大量工作,并且动画不如使用数学公式准确

  • BackEase:动画开始在指定路径上运动前稍微收缩动画的运行。

  • BounceEase:创建弹跳效果。

  • CircleEase:使用圆函数创建加速和/或减速的动画。

  • CubicEase:使用公式 f(t) = t^3 创建加速和/或减速的动画。

  • ElasticEase:创建一个动画,模拟弹簧的来回振荡运动,直到它达到停止状态。

  • ExponentialEase:使用指数公式创建加速和/或减速的动画。

  • PowerEase:使用公式 f(t) = t^p 创建加速和/或减速的动画,其中 p 等于 Power 属性。

  • QuadraticEase:使用公式 f(t) = t^2 创建加速和/或减速的动画。

  • QuarticEase:使用公式 f(t) = t^4 创建加速和/或减速的动画。

  • QuinticEase:使用公式 f(t) = t^5 创建加速和/或减速的动画。

  • SineEase:使用正弦公式创建加速和/或减速的动画。

BackEase

cs 复制代码
<BackEase Amplitude="1" EasingMode="EaseOut" />

BounceEase

cs 复制代码
<BounceEase
    Bounces="2"
    Bounciness="2"
    EasingMode="EaseOut" />

CircleEase

cs 复制代码
<CircleEase EasingMode="EaseOut"/>

CubicEase

cs 复制代码
<CubicEase EasingMode="EaseOut"/>

ElasticEase

cs 复制代码
 <ElasticEase Oscillations="3" Springiness="1" EasingMode="EaseOut"/>

ExponentialEase

cs 复制代码
 <ExponentialEase Exponent="6" EasingMode="EaseOut"/>

PowerEase

cs 复制代码
<PowerEase Power="20" EasingMode="EaseOut"/>

QuadraticEase

cs 复制代码
<QuadraticEase EasingMode="EaseOut"/>

QuarticEase

cs 复制代码
<QuarticEase EasingMode="EaseOut"/>

QuinticEase

cs 复制代码
<QuinticEase EasingMode="EaseOut"/>

SineEase

cs 复制代码
<SineEase EasingMode="EaseOut"/>

3.1、自定义缓动函数

除了使用包含在运行时中的缓动函数,还可以通过从 EasingFunctionBase 继承来创建自己的自定义缓动函数。 以下示例演示如何创建简单的自定义缓动函数。 可以通过重写 EaseInCore 方法来为缓动函数的行为方式添加自己的数学逻辑。
Power(7)

cs 复制代码
public class CustomSeventhPowerEasingFunction : EasingFunctionBase
{
    public CustomSeventhPowerEasingFunction()
        : base() { }

    protected override double EaseInCore(double normalizedTime)
    {
        return Math.Pow(normalizedTime, 7);
    }

    protected override Freezable CreateInstanceCore()
    {
        return new CustomSeventhPowerEasingFunction();
    }
}

xaml:
<DoubleAnimation.EasingFunction>
    <demoapp:CustomSeventhPowerEasingFunction EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>

4、路径动画

路径动画是一种使用 PathGeometry 作为输入的 AnimationTimeline。 可以定义一个几何路径并使用它来设置路径动画的 PathGeometry 属性,而不是设置 From、To 或 By 属性(如对 From/To/By 动画所执行的操作)或使用关键帧(如用于关键帧动画)。 路径动画运行时,会从路径中读取 x、y 和角度信息并使用该信息生成其输出。

DoesRotateWithTangent 属性设置为 true,因此矩形会沿着路径的切线旋转
路径动画

cs 复制代码
<Window.Resources>
    <Storyboard x:Key="story1">
        <MatrixAnimationUsingPath
            DoesRotateWithTangent="True"
            RepeatBehavior="Forever"
            Storyboard.TargetName="MyMatrixTransform"
            Storyboard.TargetProperty="Matrix"
            Duration="0:0:5">
            <MatrixAnimationUsingPath.PathGeometry>
                <PathGeometry Figures="M 10,100 C 35,0 135,0 160,100 180,190 285,200 310,100" />
            </MatrixAnimationUsingPath.PathGeometry>
        </MatrixAnimationUsingPath>
    </Storyboard>
    <Storyboard
        x:Key="story2"
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X">
        <DoubleAnimation To="0" Duration="0:0:0.5" />
    </Storyboard>
</Window.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <Label Name="label" Content="Label">
        <Label.RenderTransform>
            <MatrixTransform x:Name="MyMatrixTransform">
                <MatrixTransform.Matrix>
                    <Matrix />
                </MatrixTransform.Matrix>
            </MatrixTransform>
        </Label.RenderTransform>
        <Label.Triggers>
            <EventTrigger RoutedEvent="MouseEnter">
                <BeginStoryboard Storyboard="{StaticResource story1}" />
            </EventTrigger>
        </Label.Triggers>
    </Label>
</Grid>

4.1、WPF 提供以下路径动画类

属性类型 相应的路径动画类 示例
Double DoubleAnimationUsingPath 沿着路径针对对象进行动画处理(双重动画)
Matrix MatrixAnimationUsingPath 沿着路径针对对象进行动画处理(矩阵动画)
Point PointAnimationUsingPath 沿着路径针对对象进行动画处理(点动画)

MatrixAnimationUsingPath 从其 PathGeometry 生成 Matrix 值。 与 MatrixTransform 一起使用时,MatrixAnimationUsingPath 可以沿路径移动对象。 如果将 MatrixAnimationUsingPathDoesRotateWithTangent 属性设置为 true,它还会沿路径曲线旋转对象。

PointAnimationUsingPath 从其 PathGeometry 的 x 和 y 坐标生成 Point 值。 通过使用 PointAnimationUsingPath 对采用 Point 值的属性进行动画处理,可以沿路径移动对象。 PointAnimationUsingPath 不能旋转对象

DoubleAnimationUsingPath 从其 PathGeometry 生成 Double 值。 通过设置 Source 属性,可以指定 DoubleAnimationUsingPath 是使用 x 坐标、y 坐标还是路径的角度作为其输出。 可以使用 DoubleAnimationUsingPath来沿着 x 轴或 y 轴旋转或移动对象。

4.2、路径输入

每个路径动画类提供了 PathGeometry 属性,用于指定其输入。 路径动画使用 PathGeometry 生成其输出值。 PathGeometry 类能够描述组成弧线、曲线和直线的多个复杂图形。

PathGeometry 的核心是 PathFigure 对象的集合;这些对象之所以如此命名,是因为每个图都描述了 PathGeometry 中的一个离散形状。 每个 PathFigure 都由一个或多个 PathSegment 对象组成,其中每一个都描述了图的一个线段。

线段类型 说明
ArcSegment 在两点之间创建一条椭圆弧。
BezierSegment 创建两个点之间的三次方贝塞尔曲线。
LineSegment 创建两个点之间的直线。
PolyBezierSegment 创建一系列三次方贝塞尔曲线。
PolyLineSegment 创建一系列直线。
PolyQuadraticBezierSegment 创建一系列二次贝塞尔曲线。
QuadraticBezierSegment 创建一条二次贝塞尔曲线。

5、动画触发/开始

若要使用 Storyboard 组织和应用动画,可以将动画添加为 Storyboard 的子时间线。 Storyboard 类提供 Storyboard.TargetNameStoryboard.TargetProperty 附加属性。 可以在动画上设置这些属性以指定其目标对象和属性。

若要将动画应用于其目标,可以使用触发器操作或方法来开始 Storyboard。 在 XAML 中,将 BeginStoryboard 对象与 EventTriggerTriggerDataTrigger 一起使用。 在代码中,还可以使用 Begin 方法。

情节提要开始时使用... 基于实例 样式 控件模板 数据模板 示例
BeginStoryboardEventTrigger 使用情节提要对属性进行动画处理
BeginStoryboardTrigger 属性 在属性值更改时触发动画
BeginStoryboardMultiTrigger 属性 MultiTrigger 类示例
BeginStoryboardDataTrigger 如何:在数据更改时触发动画
BeginStoryboardMultiDataTrigger MultiDataTrigger 类示例
Begin 方法 No 使用情节提要对属性进行动画处理

6、其他指导

6.1、加速减速

AccelerationRatioDecelerationRatio 设置的动画进行动画加减速处理。

6.2、重复循环中累加动画值

使用 IsCumulative 属性可在重复的周期中累积动画的基值。

可能需要设置AotoReverse = "True",让其自动还原,并设置From初始值,不然也会导致结果持续叠加。
PowerRase

cs 复制代码
 <DoubleAnimation
     AutoReverse="True"
     IsCumulative="True"
     RepeatBehavior="4x"
     From="0"
     To="20"
     Duration="0:0:0.5">
     <DoubleAnimation.EasingFunction>
         <PowerEase EasingMode="EaseOut" Power="2" />
     </DoubleAnimation.EasingFunction>
 </DoubleAnimation>

6.3、将动画终值设为下次的起始值

IsAdditive 属性指定是否要将动画的输出值添加到动画属性的起始值(基值)。

cs 复制代码
<DoubleAnimation
   IsAdditive="True"
    From="0"
    To="20"
    Duration="0:0:0.5">
    <DoubleAnimation.EasingFunction>
        <PowerEase EasingMode="EaseOut" Power="2" />
    </DoubleAnimation.EasingFunction>
</DoubleAnimation>

6.4、如何添加动画

6.4.1、控件的EventTrigger

对透明度动画时,TargetProperty写作:(Button.Opacity),(Brush.Opacity)

cs 复制代码
          <EventTrigger RoutedEvent="Button.Click">
            <BeginStoryboard>
              <Storyboard>           
                <DoubleAnimation Storyboard.TargetName="myWidthAnimatedButton"
                  Storyboard.TargetProperty="Width"
                  From="200" To="300" Duration="0:0:3" />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger>

6.4.2、控件模板ControlTemplate:EventTrigger、Trigger

cs 复制代码
      <ControlTemplate.Triggers>
        <!-- Event Trigger Example -->
        <EventTrigger RoutedEvent="Border.MouseEnter" SourceName="innerBorder">
          <BeginStoryboard>
            <Storyboard>
              <ColorAnimation
                Storyboard.TargetName="innerBorderBackgroundBrush"
                Storyboard.TargetProperty="Color"
                From="White" To="#CCCCFF"
                Duration="0:0:3" AutoReverse="True" />
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>

        <!-- Property Trigger Example -->
        <Trigger Property="IsMouseOver" Value="True" SourceName="contentPanel">
          <Trigger.EnterActions>
            <BeginStoryboard>
              <Storyboard>
                <ColorAnimation 
                  Storyboard.TargetName="contentPanelBrush" 
                  Storyboard.TargetProperty="Color"
                  To="Purple" Duration="0:0:1" />
              </Storyboard>
            </BeginStoryboard>
          </Trigger.EnterActions>
          <Trigger.ExitActions>
            <BeginStoryboard>
              <Storyboard>
                <ColorAnimation 
                  Storyboard.TargetName="contentPanelBrush" 
                  Storyboard.TargetProperty="Color"
                  To="White" Duration="0:0:1" />
              </Storyboard>
            </BeginStoryboard>
          </Trigger.ExitActions>
        </Trigger>
      </ControlTemplate.Triggers>

6.4.3、样式Style:EventTrigger

cs 复制代码
     <Style.Triggers>
       <!-- Animates the button's opacity on mouse over. -->
        <EventTrigger RoutedEvent="Button.MouseEnter">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <DoubleAnimation
                  Storyboard.TargetProperty="(Button.Opacity)"
                  From="1.0" To="0.5" Duration="0:0:0.5" AutoReverse="True"
                  RepeatBehavior="Forever" />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>  
        
        <!-- Returns the button's opacity to 1 when the mouse leaves. -->
        <EventTrigger RoutedEvent="Button.MouseLeave">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <DoubleAnimation
                  Storyboard.TargetProperty="(Button.Opacity)"
                  To="1" Duration="0:0:0.1" />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>   
        
        <!-- Changes the button's color when clicked. 
             Notice that the animation can't target the
             SolidColorBrush used to paint the button's background
             directly. The brush must be accessed through the button's
             Background property. -->
        <EventTrigger RoutedEvent="Button.Click">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <ColorAnimation 
                  Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)"
                  From="Orange" To="White" Duration="0:0:0.1" AutoReverse="True" />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>  
      </Style.Triggers>

6.5、动画终值保持并触发事件

处理 Completed 事件即可。

cs 复制代码
<DoubleAnimation
    From="0"
    To="20"
    FillBehavior="HoldEnd"
    Completed="DoubleAnimation_Completed"
    Duration="0:0:0.5"/>

6.6、不同起始时间的动画管理

同一个动画时间线中中可能会有许多个动画,这些动画的起始时间不同,为方便管理,可以使用 ParallelTimeline 对象来简化动画。每个 ParallelTimeline 都有自己的 BeginTime,并且 ParallelTimeline 的所有子元素都相对于此 BeginTime 开始,所以可以更好地封装时间。

cs 复制代码
         <Storyboard>
            <DoubleAnimation Storyboard.TargetName="FirstTextBlockSkew"
            Storyboard.TargetProperty="AngleX" Duration="0:0:1" BeginTime="0:0:2" From="0" To="45" />
            <ParallelTimeline BeginTime="0:0:4">
              <DoubleAnimation Storyboard.TargetName="SecondTextBlock"
              Storyboard.TargetProperty="Opacity" Duration="0:0:2" From="0" To="1" />
              <DoubleAnimation Storyboard.TargetName="SecondTextBlockSkew"
              Storyboard.TargetProperty="AngleX" Duration="0:0:2" From="90" To="180" />
            </ParallelTimeline>
          </Storyboard>

6.7、动画的过渡方式

对这样的场景:当鼠标光标移到它们上方时它们会放大,而当光标移开时它们会变小。 如果将鼠标悬停在按钮上,然后快速移开光标,则会在第一个动画完成之前应用第二个动画。 当两个动画像这样重叠时,应该如何处理过渡。 Compose 值合并了重叠动画,使动画之间的过渡更加平滑,而 SnapshotAndReplace 值使新动画立即替换之前的重叠动画。

cs 复制代码
<BeginStoryboard HandoffBehavior="Compose">

Compose
SnapshotAndReplace

相关推荐
小白6 小时前
WPF自定义Dialog模板,内容用不同的Page填充
wpf
Crazy Struggle10 小时前
C# + WPF 音频播放器 界面优雅,体验良好
c#·wpf·音频播放器·本地播放器
He BianGu1 天前
笔记:简要介绍WPF中FormattedText是什么,主要有什么功能
笔记·c#·wpf
脚步的影子2 天前
.NET 6.0 + WPF 使用 Prism 框架实现导航
.net·wpf
jyl_sh2 天前
Ribbon (WPF)
ribbon·wpf·client·桌面程序开发·c/s客户端
wo63704312 天前
[Visual Stuidio 2022使用技巧]2.配置及常用快捷键
c#·.net·wpf
小黄人软件2 天前
wpf 字符串 与 变量名或函数名 相互转化:反射
wpf
界面开发小八哥2 天前
DevExpress WPF中文教程:如何解决排序、过滤遇到的常见问题?(二)
.net·wpf·界面控件·devexpress·ui开发
Vae_Mars2 天前
WPF中图片的宫格显示
wpf