WPF 动画

        动画的本质就是在一个时间段内对象位置、角度、颜色、透明度等属性值的连续变化。这些属性种,有些是对象自身的单属性,有些是图形变形 的属性。WPF规定,可以用来制作动画的属性必须是依赖属性。
        动画就是“会动的画”,而这个会动值得就是能够让UI元素或元素变形的某个属性值产生连续变化。任何一个属性都有自己的数据类型,比如UIElement的With和Height属性为Double类型、Window的Title属性为String类型。几乎针对每个可能的数据类型,WPF的动画子系统都为其准备了相应的动画类,这些动画类均派生自AnimationTimeline。3种具体动画,即简单动画关键帧动画沿路径运动的动画。例如:DoubleAnimationbase,它完整地派生了3个具体动画:DoubleAnimation、DoubleAnimationUsingKeyFrames和DoubleAnimationUsingPath,分别是简单动画、关键帧动画、沿路径运动的动画。

动画由下面几部分组成:

高级动画

使用From、To、By、Duration几个属性进行组合就可以制作很多不同效果的动画了,然而WPF动画系统提供的控制属性远不止这些。

 

实例,一个矩形实现淡入淡出效果:

 

方式一,前端代码实现:

<!--对其属性进行Opacity动画处理,鼠标移入显示淡出的效果-->
<Rectangle
  Name="MyRectangle"
  Width="100" 
  Height="100"
  Fill="Blue">
  <Rectangle.Triggers>
    <!-- Animates the rectangle's opacity. -->
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation
            Storyboard.TargetName="MyRectangle" 
            Storyboard.TargetProperty="Opacity"
            From="1.0" To="0.0" Duration="0:0:5" 
            AutoReverse="True" RepeatBehavior="Forever" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

方式二,后台代码实现:

    public partial class AnimationDemo : Window
    {
        private Storyboard myStoryboard;
        public AnimationDemo()
        {
            InitializeComponent();
            StackPanel myPanel = new StackPanel();
            myPanel.Margin = new Thickness(10);

            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "myRectangle";
            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            myRectangle.Fill = Brushes.Blue;

            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 1.0;
            myDoubleAnimation.To = 0.0;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));

            //设置AutoReverse属性,如果将该属性设置为true,将会反向运动
            //myDoubleAnimation.AutoReverse = true;
            //重复动画
            //myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;

            myDoubleAnimation.FillBehavior = FillBehavior.HoldEnd;
            myDoubleAnimation.Completed += MyDoubleAnimation_Completed;

            myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.OpacityProperty));

            // Use the Loaded event to start the Storyboard.
            myRectangle.Loaded += new RoutedEventHandler(myRectangleLoaded);
            myPanel.Children.Add(myRectangle);
            this.Content = myPanel;
        }
        private void MyDoubleAnimation_Completed(object sender, EventArgs e)
        {
            MessageBox.Show("动画完成");
        }
        /// <summary>
        /// 动画完成事件,使用Completed事件时,不能设置动画重复且要将事件设置BeginAnimation()方法之前,否则不起作用。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void myRectangleLoaded(object sender, RoutedEventArgs e)
        {
            myStoryboard.Begin(this);
        }
    }

关键帧动画
        动画是UI元素属性连续改变所产生的视觉效果。属性每次细微的变化都会产生一个新的画面,每个新画面就称为一“帧”,帧的连续播放就产生动画的效果。关键帧动画允许程序员为一段动画设置几个里程碑,动画执行到里程碑所在的时间点时,被动画所控制的属性值也必须达到设定的值,这些时间线上的里程碑就是关键帧。

实例:
一个Button在单击后用900毫秒的时长从左上角移动到右下角,但移动路线不是直接移动而是走“Z”字形。我们只需创建两个DoubleAnimationUsingKeyFrames实例,一个控制TranslateTransform的X属性,一个控制TranslateTransform的Y属性。每个DoubleAnimationUsingKeyFrames各拥有三个关键帧用于指明X或Y在三个时间点(两个拐点和终点)应该达到什么样的值。

 程序的XAML代码如下:

 <Button Width="60" Height="60" Content="Move" Click="Button_Click" 
     HorizontalAlignment="Left" VerticalAlignment="Top">
     <Button.RenderTransform>
         <TranslateTransform x:Name="tt" X="30" Y="30"/>
     </Button.RenderTransform>
 </Button>

后台代码如下:

        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.FromTimeSpan(TimeSpan.FromMilliseconds(300));
            x_kf_1.Value = 200;
            x_kf_2.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(600));
            x_kf_2.Value = 0;
            x_kf_3.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(900));
            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);

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

        }

特殊的关键帧
DoubleAnimationUsingKeyFrames 的KeyFrames 属性的数据类型是DoubleKeyFrameCollection,此集合类可接收的类型为 DoubleKeyFrame。DoubleKeyFrame 是一个抽象类,它的所有派生类如下:

  • LinearDoubleKeyFrame:线性变化关键帧,目标属性值的变化时是直线性的、均匀的,即变化速率不变。
  • DiscreteDoubleKeyFrame:不连续变化关键帧,目标属性值的变化是跳跃性的、跃迁的。
  • SplineDoubleKeyFrame:样条函数式变化关键帧,目标属性的变化速率是一条贝塞尔曲线。
  • EasingDoubleKeyFrame:缓冲式变化关键帧,目标属性以某种缓冲形式变化。

        4个派生类中最常用的是SplineDoubleKeyFrame。可以非常方面的制作非匀速动画,因为他使用一条贝塞尔曲线来控制目标属性值的变化速率。这条用于控制变化速率的贝塞尔曲线的起点是(0,0)和(1,1),分别映射着目标属性的变化起点和变化终点,意思是目标属性值由0%变化到100%。这条曲线的有两个控制点ControlPoint1和ControlPoint2,意思是曲线从起点出发先向ControlPoint1的方向前进、再向ControlPoint2的方向前进、最后到达终点,形成一条平滑的曲线。如果设置ControlPoint1和ControlPoint2的横纵坐标值相等,这是曲线成为一条直线,SplineDoubleKeyFrame和LinearDoubleKeyFrame是等价的。
下面是SplineDoubleKeyFrame的实例,程序的XAML代码如下:

<Button x:Name="btnSpecial" Width="60" Height="60" Content="Move" Click="btnSpecial_Click"
    HorizontalAlignment="Left" VerticalAlignment="Top">
    <Button.RenderTransform>
        <TranslateTransform x:Name="translate" X="30" Y="30"/>
    </Button.RenderTransform>
</Button>

后台代码如下:

        private void btnSpecial_Click(object sender, RoutedEventArgs e)
        {
            // 创建动画
            DoubleAnimationUsingKeyFrames dakX = new DoubleAnimationUsingKeyFrames();
            dakX.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
            //创建、添加关键帧
            SplineDoubleKeyFrame kf = new SplineDoubleKeyFrame();
            kf.KeyTime = KeyTime.FromPercent(1);
            kf.Value = 400;
            //设置速率
            KeySpline ks = new KeySpline();
            ks.ControlPoint1 = new Point(0, 1);
            ks.ControlPoint2 = new Point(1, 0);
            kf.KeySpline = ks;
            dakX.KeyFrames.Add(kf);
            //执行动画
            this.translate.BeginAnimation(TranslateTransform.XProperty, dakX);
        }

路径动画
        如何让目标对象沿着一条给定的路径移动呢?答案是使用DoubleAnimationUsingPath类。DoubleAnimationUsingPath需要一个PathGeometry来指明移动路径,PathGeometry的数据信息可以用XAML的Path语法书写。PathGeometry的另一个重要属性是Source,Source属性的数据类型是PathAnimationSource枚举,枚举值可取X(关注曲线上每一点横坐标的变化)、Y(关注曲线上每一点纵坐标的变化)或Angle关注曲线上每一点处切线方向的变化。
实例:让Button沿着一条贝塞尔曲线做波浪形运动。

 

程序XAML代码如下:

<Grid>
        <Grid x:Name="LayoutRoot">
            <!--移动路径-->
            <Grid.Resources>
                <PathGeometry x:Key="movingPath" 
            	Figures="M 0,150 C 300,-100 300,400 600,120"/>
            </Grid.Resources>
            <Button Content="Move" HorizontalAlignment="Left" VerticalAlignment="Top"
                Width="80" Height="80" Click="Button_Click">
                <Button.RenderTransform>
                    <TranslateTransform x:Name="tt" X="0" Y="0"/>
                </Button.RenderTransform>
            </Button>
        </Grid>
</Grid>

后台代码如下:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // 查找资源
            PathGeometry pg = this.LayoutRoot.FindResource("movingPath") as PathGeometry;
            Duration duration = new Duration(TimeSpan.FromMilliseconds(600));// 设置动画时间
            // 创建动画
            DoubleAnimationUsingPath dapX = new DoubleAnimationUsingPath();
            dapX.PathGeometry = pg;
            dapX.Source = PathAnimationSource.X;
            dapX.Duration = duration;

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

            //设置来回循环效果
            dapX.AutoReverse = true;
            dapX.RepeatBehavior = RepeatBehavior.Forever;
            dapY.AutoReverse = true;
            dapY.RepeatBehavior = RepeatBehavior.Forever;
            //执行动画
            this.tt.BeginAnimation(TranslateTransform.XProperty, dapX);
            this.tt.BeginAnimation(TranslateTransform.YProperty, dapY);
        }

场景
        场景就是并行执行的一组动画。先是把一组独立的动画组织在一个Storyboard元素中、安排好他们的协作关系,然后制定哪个动画由哪个UI元素、哪个属性负责完成。Storyboard设计好后,你可以为他选择一个恰当的触发时机,比如按钮按下或下载开始时。一旦触发条件被满足,动画产经就会开始执行。实例:


程序XAML代码如下:

 

<Grid Margin="6">
        <!--布局控制-->
        <Grid.RowDefinitions>
            <RowDefinition Height="38"/>
            <RowDefinition Height="38"/>
            <RowDefinition Height="38"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="60"/>
        </Grid.ColumnDefinitions>
        <!--跑道红-->
        <Border BorderBrush="Gray" BorderThickness="1" Grid.Row="0">
            <Ellipse x:Name="ballR" Height="36" Width="36" Fill="Red"
                     HorizontalAlignment="Left">
                <Ellipse.RenderTransform>
                    <TranslateTransform x:Name="ttR"/>
                </Ellipse.RenderTransform>
            </Ellipse>
        </Border>
        <!--跑道绿-->
        <Border BorderBrush="Gray" BorderThickness="1,0,1,1" Grid.Row="1">
            <Ellipse x:Name="ballG" Height="36" Width="36" Fill="LawnGreen"
                     HorizontalAlignment="Left">
                <Ellipse.RenderTransform>
                    <TranslateTransform x:Name="ttG"/>
                </Ellipse.RenderTransform>
            </Ellipse>
        </Border>
        <!--跑道蓝-->
        <Border BorderBrush="Gray" BorderThickness="1,0,1,1" Grid.Row="2">
            <Ellipse x:Name="ballB" Height="36" Width="36" Fill="Blue"
                     HorizontalAlignment="Left">
                <Ellipse.RenderTransform>
                    <TranslateTransform x:Name="ttB"/>
                </Ellipse.RenderTransform>
            </Ellipse>
        </Border>
        <!--按钮-->
        <Button Content="Go!" Grid.Column="1" Grid.RowSpan="3">
            <!--按钮触发-->
            <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"/>
                            <!--绿色小球动画-->
                            <DoubleAnimationUsingKeyFrames Duration="0:0:0.6"
                        Storyboard.TargetName="ttG" Storyboard.TargetProperty="X">
                                <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400"
                                          KeySpline="0,1,1,0"/>
                            </DoubleAnimationUsingKeyFrames>
                            <!--蓝色小球动画-->
                            <DoubleAnimationUsingKeyFrames Duration="0:0:0.6"
                        Storyboard.TargetName="ttB" Storyboard.TargetProperty="X">
                                <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400"
                                          KeySpline="1,0,0,1"/>
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
    </Grid>

 参考:

WPF动画详解_wpf 动画_未来无限的博客-CSDN博客

实例地址:https://download.csdn.net/download/lvxingzhe3/87656988

Style样式中根据属性或事件添加动画实例:https://download.csdn.net/download/lvxingzhe3/34831843

动画合集:WPF动画合集各类型动画demo-C#文档类资源-CSDN下载

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

无熵~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值