12.WPF动画

12.WPF动画

动画的就是在UI元素上施加一些Timeline实例。WPF把简单的动画称为AnimationTimeline,复杂的动画称为Storyboard。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T78Nidc1-1668254340754)(12.WPF动画.assets/image-20221112185754173.png)]

简单的独立动画

简单线性动画

WPF中动画系统中Dloble类型的属性用的最多,所以以DoubleAnimationBase为例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R6Ihntko-1668254340755)(12.WPF动画.assets/image-20221112190850545.png)]

  • 变化时间(Duration):必须制定,类型为Duration
  • 变化终点(To):如果没有指定,采用上一次动画的终点或者默认值
  • 变化幅度(By):如果指定了变化终点,变化幅度将被忽略
  • 变化起点(From):如果没有指定变化起点,则以变化目标的属性当前值为起点
<Grid>
    <Button Width="80" Height="80" HorizontalAlignment="Left" VerticalAlignment="Top" Click="Button_Click">
        <Button.RenderTransform>
            <TranslateTransform X="0" Y="0" x:Name="tt"></TranslateTransform>
        </Button.RenderTransform>
    </Button>
</Grid>

改变TranslateTransform对象X,Y的属性就会让Button的显示位置(非实际位置)改变

private void Button_Click(object sender, RoutedEventArgs e)
{
    DoubleAnimation daX = new DoubleAnimation();
    DoubleAnimation daY = new DoubleAnimation();
    //指定起点
    daX.From = 0;
    daY.From = 0;
    //指定终点
    Random r = new Random();
    daX.To = r.NextDouble() * 300;
    daY.To = r.NextDouble() * 300;
    //指定时长
    Duration duration = new Duration(TimeSpan.FromMilliseconds(300));
    daX.Duration = duration;
    daY.Duration = duration;
    //动画主体是TranslateTransform变形,而不是Button
    this.tt.BeginAnimation(TranslateTransform.XProperty, daX);
    this.tt.BeginAnimation(TranslateTransform.YProperty, daY);
}

在这里插入图片描述

高级动画控制

除了From、To等属性还具有一下高级属性

属性描述
AccelerationRatio加速度,0-1且与DecelerationRatio和不大于1
DecelerationRatio减速度,0-1且与DecelerationRatio和不大于1
SpeedRatio快进和慢进
AutoReverse倒放
RepeatBehavior重复,0为不播放,n为播放n次。RepeatBehavior.Forever为循环
BeginTime播放前等待时间
EasingFunction缓冲式渐变

只需在上面的代码中加入

BounceEase be = new BounceEase();
be.Bounces = 3;//弹跳3次
be.Bounciness = 3;//弹跳程度,值越大反弹越低
daY.EasingFunction = be;

在这里插入图片描述

关键帧

将上面案例的Button设置按照Z字型移动

private void Button_Click(object sender, RoutedEventArgs e)
{

    DoubleAnimationUsingKeyFrames dakX = new DoubleAnimationUsingKeyFrames();
    DoubleAnimationUsingKeyFrames dakY = new DoubleAnimationUsingKeyFrames();

    //设置动画总时长
    dakX.Duration = new Duration(TimeSpan.FromMilliseconds(900));
    dakY.Duration = new Duration(TimeSpan.FromMilliseconds(900));
    //创建,添加关键帧
    LinearDoubleKeyFrame x_kf_1 = new LinearDoubleKeyFrame();
    LinearDoubleKeyFrame x_kf_2 = new LinearDoubleKeyFrame();
    LinearDoubleKeyFrame x_kf_3 = new LinearDoubleKeyFrame();
    x_kf_1.KeyTime = KeyTime.FromPercent(0.33);
    x_kf_1.Value = 200;
    x_kf_2.KeyTime = KeyTime.FromPercent(0.66);
    x_kf_2.Value = 0;
    x_kf_3.KeyTime = KeyTime.FromPercent(1);
    x_kf_3.Value = 200;
    dakX.KeyFrames.Add(x_kf_1);
    dakX.KeyFrames.Add(x_kf_2);
    dakX.KeyFrames.Add(x_kf_3);

    LinearDoubleKeyFrame y_kf_1 = new LinearDoubleKeyFrame();
    LinearDoubleKeyFrame y_kf_2 = new LinearDoubleKeyFrame();
    LinearDoubleKeyFrame y_kf_3 = new LinearDoubleKeyFrame();
    y_kf_1.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
    y_kf_1.Value = 0;
    y_kf_2.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(600));
    y_kf_2.Value = 180;
    y_kf_3.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(900));
    y_kf_3.Value = 180;
    dakY.KeyFrames.Add(y_kf_1);
    dakY.KeyFrames.Add(y_kf_2);
    dakY.KeyFrames.Add(y_kf_3);

    //执行动画
    tt.BeginAnimation(TranslateTransform.XProperty, dakX);
    tt.BeginAnimation(TranslateTransform.YProperty, dakY);
}

在这里插入图片描述

路径动画

让目标沿着给定的路径移动,使用DoubleAnimationUsingPath,需要一个PathGeometry来指定路径,PathGeometry的另一个重要属性是Source,枚举值为X\Y\Angle,例如Angle则表示关注曲线上每一点处切线方向的变化。

实例:让一个Button沿着路径移动

<Grid x:Name="layoutRoot">
    <Grid.Resources>
        <!--移动路径-->
        <PathGeometry x:Key="movePath" Figures="M 0,50 C 300,-100 300,400 600,120"></PathGeometry>
    </Grid.Resources>
    <Button Content="Move" Width="80" Height="80" HorizontalAlignment="Left" VerticalAlignment="Top" Click="Button_Click">
        <Button.RenderTransform>
            <TranslateTransform X="0" Y="0" x:Name="tt"></TranslateTransform>
        </Button.RenderTransform>
    </Button>
</Grid>
private void Button_Click(object sender, RoutedEventArgs e)
{
    //从XAML代码中获取移动路径数据
    PathGeometry pg = this.layoutRoot.FindResource("movePath") as PathGeometry;
    Duration duration = new Duration(TimeSpan.FromMilliseconds(600));

    //创建动画
    DoubleAnimationUsingPath dpX = new DoubleAnimationUsingPath();
    dpX.Duration = duration;
    dpX.PathGeometry = pg;
    dpX.Source = PathAnimationSource.X;

    DoubleAnimationUsingPath dpY = new DoubleAnimationUsingPath();
    dpY.Duration = duration;
    dpY.PathGeometry = pg;
    dpY.Source = PathAnimationSource.Y;

    dpX.AutoReverse = true;
    dpX.RepeatBehavior = RepeatBehavior.Forever;
    dpY.AutoReverse = true;
    dpY.RepeatBehavior = RepeatBehavior.Forever;

    //执行动画
    this.tt.BeginAnimation(TranslateTransform.XProperty,dpX);
    this.tt.BeginAnimation(TranslateTransform.YProperty,dpY); 
}

在这里插入图片描述

场景

场景就是并行执行一组动画,WPF会把一组动画组织在Stroyboard中,安排好它们的协作关系。

制作3个小球执行不同动画的场景

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MuS0e42v-1668254340757)(12.WPF动画.assets/image-20221112195045207.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eDFnv0wP-1668254340758)(12.WPF动画.assets/5.gif)]
在这里插入图片描述

<Window x:Class="WpfApplication1.Window64"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window64" Height="159" Width="461">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="38" />
            <RowDefinition Height="38" />
            <RowDefinition Height="38" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="60" />
        </Grid.ColumnDefinitions>
        <!--跑道(红)-->
        <Border Grid.Row="0" BorderBrush="Gray" BorderThickness="1">
            <Ellipse Width="36" Height="36" Fill="Red" HorizontalAlignment="Left" x:Name="ballR">
                <Ellipse.RenderTransform>
                    <TranslateTransform X="0" Y="0" x:Name="ttR">
                    </TranslateTransform>
                </Ellipse.RenderTransform>
            </Ellipse>
        </Border>
        <!--跑道(绿)-->
        <Border Grid.Row="1" BorderBrush="Gray" BorderThickness="1,0,1,1">
            <Ellipse Width="36" Height="36" Fill="Green" HorizontalAlignment="Left" x:Name="ballG">
                <Ellipse.RenderTransform>
                    <TranslateTransform X="0" Y="0" x:Name="ttG">
                    </TranslateTransform>
                </Ellipse.RenderTransform>
            </Ellipse>
        </Border>
        <!--跑道(蓝)-->
        <Border Grid.Row="2" BorderBrush="Gray" BorderThickness="1,0,1,1">
            <Ellipse Width="36" Height="36" Fill="Blue" HorizontalAlignment="Left" x:Name="ballB">
                <Ellipse.RenderTransform>
                    <TranslateTransform X="0" Y="0" x:Name="ttB">
                    </TranslateTransform>
                </Ellipse.RenderTransform>
            </Ellipse>
        </Border>
        <!--按钮-->
        <Button Content="Go" Grid.RowSpan="3" Grid.Column="1" Click="Button_Click"/>
    </Grid>
</Window>
private void Button_Click(object sender, RoutedEventArgs e)
{
    Duration duration = new Duration(TimeSpan.FromMilliseconds(600));

    //红色小球匀速运动
    DoubleAnimation daRx = new DoubleAnimation();
    daRx.Duration = duration;
    daRx.To = 400;

    //绿色小球做变速运动
    DoubleAnimationUsingKeyFrames dakGx = new DoubleAnimationUsingKeyFrames();
    dakGx.Duration = duration;
    SplineDoubleKeyFrame kfg = new SplineDoubleKeyFrame(400,KeyTime.FromPercent(1));
    kfg.KeySpline = new KeySpline(1,0,0,1);
    dakGx.KeyFrames.Add(kfg);

    //蓝色小球变速运动
    DoubleAnimationUsingKeyFrames dakBx = new DoubleAnimationUsingKeyFrames();
    dakBx.Duration = duration;
    SplineDoubleKeyFrame kfb = new SplineDoubleKeyFrame(400,KeyTime.FromPercent(1));
    kfb.KeySpline = new KeySpline(0,1,1,0);
    dakBx.KeyFrames.Add(kfb);

    //创建场景
    Storyboard storyBoard = new Storyboard();
    Storyboard.SetTargetName(daRx,"ttR");
    Storyboard.SetTargetProperty(daRx, new PropertyPath(TranslateTransform.XProperty));

    Storyboard.SetTargetName(dakGx, "ttG");
    Storyboard.SetTargetProperty(dakGx, new PropertyPath(TranslateTransform.XProperty));

    Storyboard.SetTargetName(dakBx, "ttB");
    Storyboard.SetTargetProperty(dakBx, new PropertyPath(TranslateTransform.XProperty));

    storyBoard.Duration = duration;
    storyBoard.Children.Add(daRx);
    storyBoard.Children.Add(dakBx);
    storyBoard.Children.Add(dakGx);

    storyBoard.Begin(this);
    storyBoard.Completed += (a, b) => { MessageBox.Show(ttR.X.ToString()); };
}

也可以直接使用XAML晚上上面的动画,Stroyboard一般都放在UI元素的Trigger中,Trigger在触发时会执行<BeginStoryboard>标签中的实例。

<Button Content="Go" Grid.RowSpan="3" Grid.Column="1" Click="Button_Click">
    <Button.Triggers>
        <EventTrigger RoutedEvent="Button.Click">
            <BeginStoryboard>
                <Storyboard Duration="0:0:0.6">
                    <!--红色小球动画-->
                    <DoubleAnimation Duration="0:0:0.6" To="400" Storyboard.TargetName="ttR" Storyboard.TargetProperty="X">
                        
                    </DoubleAnimation>
                    <!--绿色小球动画-->
                    <DoubleAnimationUsingKeyFrames Duration="0:0:0.6" Storyboard.TargetProperty="X" Storyboard.TargetName="ttG">
                        <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400" KeySpline="1,0,0,1"></SplineDoubleKeyFrame>
                    </DoubleAnimationUsingKeyFrames>
                    <!--蓝色小球动画-->
                    <DoubleAnimationUsingKeyFrames Duration="0:0:0.6" Storyboard.TargetName="ttB" Storyboard.TargetProperty="X">
                        <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400" KeySpline="0,1,1,0"></SplineDoubleKeyFrame>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Button.Triggers>
</Button>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步、步、为营

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值