WPF绘图与动画(四)

 

  WPF规定,可以用来制作动画的属性必须是依赖属性。

  Timeline、AnimationTimeline和Storyboard

  

  ⒈简单线性动画

    所谓“简单线性动画”就是指仅由变化起点、变化终点、变化幅度、变化时间4个要素构成的动画。

      变化时间(Duration属性):必须指定,数据类型为Duration。

      变化终点(To属性):如果没有指定变化终点,程序将采用上一次动画的终点或默认值。

      变化幅度(By属性):如果同时指定了变化终点,变化幅度将被忽略。

      变化起点(From属性):如果没有指定变化起点则以变化目标属性的当前值为起点。

  

<Window x:Class="WPFLearn.DrawAndAnimation.DoubleAnimation1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DoubleAnimation" Height="300" Width="300">
    <Grid>
        <Button Content="Move!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="60" Height="60" Click="Button_OnClick">
            <Button.RenderTransform>
                <TranslateTransform x:Name="tt" X="0" Y="0"/>
            </Button.RenderTransform>
        </Button>
    </Grid>
</Window>

  

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            DoubleAnimation daX=new DoubleAnimation();
            DoubleAnimation daY=new DoubleAnimation();

            //指定起点
            daX.From = 0D;
            daY.From = 0D;
            
            //指定终点
            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);
        }

    这段代码有以下几处值得注意的地方:

      ⒈因为指定了daX和daY的起始值为0,所以每次按钮都会“跳”回窗体的左上角开始动画。如果想让按钮从当前位置开始下一次动画,只需要把“daX.From=0D;”和“daY.From=0D;”两句代码移除即可。

      ⒉尽管表现出来的是Button在移动,但DoubleAnimation的作用目标并不是Button而是TranslateTransform实例,因为TranslateTransform实例是Button的RenderTransform属性值,所以Button“看上去”是移动。

      ⒊能用来制作动画的属性必须是依赖属性,TranslateTransform的XProperty和YProperty就是两个依赖属性。

      ⒋UIElement和Animatable两个类都定义有BeginAnimation这个方法,TranslateTransform派生自Animatable类,所以具有这个方法,这个方法的调用者就是动画要作用的目标对象,两个参数分别指明被用作依赖属性(TranslateTransform.XProperty和TranslateTransform.XProperty)和设计好的动画(daX和daY),可以猜想,如果需要动画改编Button的宽度或高度(这两个属性也是Double类型),也应该先创建DoubleAnimation实例,然后设置起始值和动画时间,最后用Button的BeginAnimation方法、使用动画对象影响Buttion.WidthProperty和Button.HeightProperty。

 

    ⒉高级动画控制

      使用From、To、By、Duration几个属性进行组合就已经可以制作很多不同效果的动画了,然而WPF动画系统提供的控制苏醒远不止这些。如果想制作更加复杂或逼真的动画,还需要使用以下一些效果。

属性描述应用举例
AccelerationRatio加速速率,介于0.0和1.0之间,与DecelerationRatio之和不大于1.0模拟汽车启动
DecelerationRatio减速速率,介于0.0和1.0之间,与AccelerationRatio之和不大于1.0模拟汽车刹车
SpeedRatio动画实际播放速度与正常速度的比值快进播放、慢动作
AutoReverse是否以相反的动画方式从终止方起始值倒退播放
RepeatBehavior动画的重复行为,取0为不播放,使用double类型值可控制循环次数,取RepeatBehavior.Forever为永远循环循环播放
BeginTime正式开始播放前的等待时间多个动画之前的协同
EasingFunction缓冲式渐变乒乓球弹跳效果

      对于这些属性,大家可以自己动手尝试----对它们进行组合往往可以产生很多意想不到的效果。

      在这些属性中,EasingFunction是一个扩展性非常强的属性。它的取值是IEasingFunction接口类型,为WPF自带的IEasingFunction派生类就有十多种,每个派生类都能产生不停的结束效果。比如BounceEase可以产生乒乓球弹跳式的效果,我们可以直接拿来使用而不必花精力去亲自创作。

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            DoubleAnimation daX = new DoubleAnimation();
            DoubleAnimation daY = new DoubleAnimation();

            //设置反弹
            BounceEase be=new BounceEase();
            be.Bounces = 3; //弹跳3次
            be.Bounciness = 3; //弹性程度,值越大反弹越低
            daY.EasingFunction = be;
            
            //指定起点
            daX.From = 0D;
            daY.From = 0D;

            //指定终点
            daX.To = 300;
            daY.To = 300;

            //指定时长
            Duration duration = new Duration(TimeSpan.FromMilliseconds(3000));
            daX.Duration = duration;
            daY.Duration = duration;

            //动画的主体是TranslateTransform变形,而非Button
            this.tt.BeginAnimation(TranslateTransform.XProperty, daX);
            this.tt.BeginAnimation(TranslateTransform.YProperty, daY);
        }

    ⒊关键帧动画

      动画是UI元素属性连续改变所产生的视觉效果。属性每次细微的变化都会产生一个新的画面,每个新画面就称为一“帧”,帧的连续播放就产生动画效果。如同电影一样,单位时间内播放的帧数越多,动画的效果就越细致。前面讲到的简单动画只设置了一个起点和终点,之间的动画帧都是由程序计算出来并绘制的,程序员无法进行控制。关键帧动画则允许程序员为一段动画设置几个“里程碑”,动画执行到里程碑所在的时间点时,被动画所控制的属性值也必须达到设定的值,这些时间线上的“里程碑”就是关键帧。

<Window x:Class="WPFLearn.DrawAndAnimation.DoubleAnimationUsingKeyFrames1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DoubleAnimationUsingKeyFrames1" Height="300" Width="300">
    <Grid>
        <Button Content="Move" VerticalAlignment="Top" HorizontalAlignment="Left" Width="80" Height="80" Click="Button_OnClick">
            <Button.RenderTransform>
                <TranslateTransform x:Name="tt" X="0" Y="0"/>
            </Button.RenderTransform>
        </Button>
    </Grid>
</Window>

  

        private void Button_OnClick(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);
        }

  使用 KeyTime.FromPercent静态方法则可以获得以百分比计算单的相对时间点,程序将整个关键帧动画的时长(Duration)视为100%。

            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.0);
            x_kf_3.Value = 200;

  之后无论你把dakX的Duration改为多少,三个关键帧都会将整个动画分割为均等的三段。

    ⒋特殊的关键帧

      DoubleAnimationUsingKeyFrames的KeyFrames属性的数据类型是DoubleKeyFrameCollection,此集合类可接收的元素类型为DoubleKeyFrame。DoubleKeyFrame是一个抽象类,前面使用的LinearDoubleKeyFrame就是它的派生类之一。DoubleKeyFrame的所有派生类如下:

    LinearDoubleKeyFrame:线性变换关键帧,目标属性值的变化是直线性的、均匀的,及变化速率不变。

    DiscreteDoubleKeyFrame:不连续变化关键帧,目标属性值的变化是跳跃性的、跃迁的。

    SplineDoubleKeyFrame:样条函数式变化关键帧,目标属性值得变化速率是一条贝塞尔曲线。

    EasingDoubleKeyFrame:缓冲式变化关键帧,目标属性值以某种缓冲形式变化。

    4个派生类中最常用的是SplineDoubleKeyFrame(SplineDoubleKeyFrame可以替代LinearDoubleKeyFrame)。

 

<Window x:Class="WPFLearn.DrawAndAnimation.SplineDoubleKeyFrame1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SplineDoubleKeyFrame1" Height="300" Width="300">
    <Grid>
        <Button Content="Move" VerticalAlignment="Top" HorizontalAlignment="Left" Width="80" Height="80" Click="Button_OnClick">
            <Button.RenderTransform>
                <TranslateTransform x:Name="tt" X="0" Y="0"/>
            </Button.RenderTransform>
        </Button>
    </Grid>
</Window>

  

        private void Button_OnClick(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.tt.BeginAnimation(TranslateTransform.XProperty,dakX);
        }

      ⒌路径动画

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

        

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            // 从XAML代码中获取移动路径数据
            System.Windows.Media.PathGeometry pg=this.LayoutRoot.FindResource("movingPath") as System.Windows.Media.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);
        }

  

<Window x:Class="WPFLearn.DrawAndAnimation.DoubleAnimationUsingPath1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DoubleAnimationUsingPath1" Height="300" Width="300">
    <Grid x:Name="LayoutRoot">
        <Grid.Resources>
            <!--移动路径-->
            <PathGeometry x:Key="movingPath" Figures="M 0,150 C300,-100 300,400 600,120"/>
        </Grid.Resources>
        <Button Content="Move" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="80" Click="Button_OnClick">
            <Button.RenderTransform>
                <TranslateTransform x:Name="tt" X="0" Y="0"/>
            </Button.RenderTransform>
        </Button>
    </Grid>
</Window>

  

转载于:https://www.cnblogs.com/bjxingch/articles/7862695.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值