WPF 动画系统

1、基本动画。
WPF提供了一个更高级的模型,通过该模型可以只关注动画的定义,而不考虑它们的渲染方式,这个模型基于依赖项属性基础架构,本质上,WPF动画只不过是在一段时间间隔内修改依赖项属性值的一种方式。不过还有另外一个限制,为了实现属性的动态化,需要有支持相应数据类型的动画类,例如Button.Width属性使用双精度数据类型,为实现属性的动态化,需要使用DoubleAnimation类,但Button.Padding属性使用的是Thickness结构,所以需要使用ThicknessAnimation类。为了为属性应用动画,可以针对相应的数据类型创建自己的动画类,你将发现,System.Windows.Media.Animation名称空间已经为希望使用的大多数数据类型提供了动画类。

2、Animation类。
实际上有两种类型的动画,一种是在开始值和结束值之间以逐步增加的方式改变属性的动画(线性插值过程),另一种是从一个值突然变成另一值得动画(关键帧动画)。所有关键帧动画都使用 "类型名 + AnimationUsingKeyFrames " 的形式进行命名,比如StringAnimationUsingKeyFrames和ObjectAnimationUsingKeyFrames。某些数据类型有关键帧动画类,但没有插值动画类。例如,可使用关键帧为字符串应用动画,不能使用插值为字符串应用动画。然而,所有数据类型都支持关键帧动画,除非他们根本不支持动画。所有具有(使用插值)常规动画类的数据类型,也都有相应的关键帧动画的动画类型,如线性插值的DoubleAnimation对应DoubleAnimationUsingKyyFrames。另外还有一种基于路径的动画。因此,WPF动画使用三种方法:线性插值、关键帧和路径。在System.Windows.Media.Animation名称空间中将发现以下内容:

7个 “类型名+Animation类” 这些类使用插值动画。

22个 “类型名+AnimationUsingKeyFrames” 这些类使用关键帧动画。

3个 "类型名+AnimationUsingPath"类这类使用基于路径的动画。

3、使用代码创建动画。
wpf中,最常用的动画技术是线性插值动画,标准的帧速率是60秒/帧,使用动画的最简单方式是实例化在前面列出的其中一个动画类,然后使用修改元素的BeginAnimation()方法,所有wpf元素,从UIElement基类开始,都继承了BeginAnimation()方法,该方法是IAnimatable接口的一部分。

xaml代码:



后台代码:

private void Button_Click(object sender, RoutedEventArgs e)
{
    //实例化一个DoubleAnimation类。
    DoubleAnimation doubleAnimation = new DoubleAnimation();
    //设置From属性。
    doubleAnimation.From = btn1.Width;
    //设置To属性。
    doubleAnimation.To = 250;
    //设置Duration属性。
    doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
    //为元素设置BeginAnimation方法。
    btn1.BeginAnimation(Button.WidthProperty, doubleAnimation);
}

WPF 动画系统_第1张图片
其中, From属性是元素的开始值,To属性是元素属性的结束值,Duration是整个动画执行的时间。即使不使用To属性,也可以使用By属性,By值被简单地增加到From值上,使其达到To值。不过,对于非数值数据类型来说,By属性是没有意义的。

4、同时发生的动画。
就是创建多个Animation动画,然后为元素设置属性。

private void Button_Click(object sender, RoutedEventArgs e)
{
    //实例化一个DoubleAnimation类。
    DoubleAnimation doubleAnimation = new DoubleAnimation();
    //设置From属性。
    doubleAnimation.From = btn1.Width;
    //设置To属性。
    doubleAnimation.To = 250;
    //设置Duration属性。
    doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
    //为元素设置BeginAnimation方法。
    btn1.BeginAnimation(Button.WidthProperty, doubleAnimation);

    //实例化一个DoubleAnimation动画,用于设置元素的高。
    DoubleAnimation doubleAnimationHeight = new DoubleAnimation();
    //设置Form属性。
    doubleAnimationHeight.From = btn1.Height;
    //设置To属性的值。
    doubleAnimationHeight.By = 70;
    //设置时间。
    doubleAnimationHeight.Duration = new Duration(TimeSpan.FromSeconds(3));
    //开始动画。
    btn1.BeginAnimation(Button.HeightProperty, doubleAnimationHeight);
}

5、动画的生命周期。
从技术的角度看,WPF动画只是暂时的,这意味着它们不能真正改变基本属性的值,当动画处于活动状态时,只是覆盖了属性的值。

单向动画,在动画运行结束后会保持处于活动状态,这是因为动画需要将按钮的宽度保持为新值,这回导致如下常见问题,如果尝试使用代码在动画完成后修改属性值,代码将不会起作用,因为代码只是为属性指定了一个新的本地值,但仍会先试用动画之后的属性值。

为了解决动画完成后能修改属性的值,有以下方法可解决。

a)、设置AutoReverse属性,如果将该属性设置为true,将会反向运动,返回原始的值(不适合动画完成后,再为属性设置最后的值,只是还原为动画之前的值)。

b)、改变FillBehavior属性。通常,FillBehavior属性设置为HoldEnd,这意味着当当动画结束时,会继续为目标元素应用最后的值。如果将FillBehavior属性改为Stop,只要动画结束,属性就会恢复为原来的值(适用于动画结束后,再次为其设置新值,一般不与AutoReverse配合着使用,这两个用其中一个就行了)。

6、动画的Completed事件。
使用Completed事件时,要将事件设置BeginAnimation()方法之前,否则不起作用。在Completed中,可通过调用BeginAnimation()方法来渲染不活动的动画,为此,只需要指定属性,并为动画对象传递null引用。

void doubleAnimationHeight_Completed(object sender, EventArgs e)
{
    MessageBox.Show("动画的高执行完毕了!!!");
    //设置空引用。
    btn1.BeginAnimation(Button.HeightProperty, null);
}

7、TimeLine类。

WPF 动画系统_第2张图片

7.1)、AccelerationRatio和DeceleRation属性。
可以通过AcclerationRation和DecelerationRation属性压缩部分时间轴,使动画运行的更快,并将拉伸其他时间进行补偿,使总时间保持不变。这两个属性都表示百分比值,例如,将AcceleRation属性设置为0.3,表示希望使用动画持续时间中前30%的时间进行加速。例如在1个10秒的动画中,前3秒会加速运行,而剩余的7秒会以恒定不变的速度运行,如果将DeceleRation属性设置为0.3,那么最后3秒回减速运行。

private void Button_Click(object sender, RoutedEventArgs e)
{
    //实例化一个DoubleAnimation类。
    DoubleAnimation doubleAnimation = new DoubleAnimation();
    //设置From属性。
    doubleAnimation.From = btn1.Width;
    //前5秒加速度运行。
    doubleAnimation.AccelerationRatio = 0.5;
    //后2秒减速运行
    doubleAnimation.DecelerationRatio = 0.2;
    //设置To属性。
    doubleAnimation.To = 1000;
    //设置Duration属性。
    doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(10));
    //为元素设置BeginAnimation方法。
    btn1.BeginAnimation(Button.WidthProperty, doubleAnimation);
}

7.2)、RepeatBehavior属性。
使用RepeataBehavior属性可以控制如何重复运行动画,如果希望重复固定次数,应为RepeatBehavior构造函数传递合适的次数。

还可设置RepeatBehavior为永久重复。 //设置重复次数为3次。 doubleAnimation.RepeatBehavior = new RepeatBehavior(3); //设置永久重复动画。 doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;

8、故事版。
WPF动画通过一组动画类表示,使用少数几个属性设置相关信息,如开始值、结束值以及持续时间。这显然使他们非常适合于XAMl,不是很清晰的是,如何为特定的事件和属性关联动画,以及如何在正确的时间触发动画。

故事板:故事板是BeginAnimation()方法的XAML等价物,通过故事板将动画指定到合适的元素和属性。

事件触发器:事件触发器响应属性变化或事件(如按钮的Click事件),并控制故事板。

故事板:
故事板是增强的时间线,可用来分组多个动画,而且具有控制动画播放的能力—暂停、停止以及播放位置。然而Storyboard类提供的最基本功能是,能够使用TargetProperty和TargetName属性指向某个特定属性和特定元素,换句话说,故事板在动画和希望应用动画的属性之间架起了一座桥梁。其中TargetProperty属性和TargetName属性都是附加属性。



    
    




    
    

事件触发器:

可以在以下4个位置定义事件触发器。

a)、在样式中(Style.Triggers集合)。

b)、在数据模板中(DataTemplate.Triggers集合)。

c)、在控件模板中(ControlTemplate.Triggers集合)。

d)、直接在元素中定义事件触发器(FrameworkElement.Triggers集合)。

当创建事件触发器时,需要指定开始触发器的路由事件和触发器执行的一个或多个动作。对于动画,最常用的动作是BeginStoryboard,该动作相当于调用BeginAnimation()方法。所有事件触发器都可以启动动作,所有动作都由继承自System.Windows.TriggerAction的类表示。

xaml代码:


WPF 动画系统_第3张图片
9、使用样式关联触发器。
有三种基本类型的WPF触发器:属性触发器、数据触发器以及事件触发器。使用触发器是关联动画的最常用方式,但并不是唯一的选择。

xaml代码:


    



    

WPF 动画系统_第4张图片
10、同步的动画。
StoryBoard类间接地继承自TimeLineGroup类,所以StoryBoard类能包含多个动画,这些动画可以作为一组进行管理,这意味着它们可以在同一时间开始。


    

    

    

WPF 动画系统_第5张图片
11、控制播放。
到目前为止,已经在事件触发器中使用了一个动作,加载动画的BeginStoryboard动作,然而,一旦创建故事版,就可以使用其他动作控制故事板,这些动作类都继承自ControllableStoryboardAction类,控制故事版的主要类如下:

WPF 动画系统_第6张图片
为成功地执行这些动作,必须在同一个Triggers集合中定义所有的触发器,如果将BeginStoryboard动作的触发器和PauseStoryboard动作的触发器放置到不同的集合中,PauseStoryboard动作就无法工作。

xaml代码:


    
        
        
            
                
                    
                
            
        

        
        
            
         
        
        
        
            
        
        
        
        
            
        

        
        
            
                
    
    
    
        
            
            
           
        
        
        
        
            
                
                
                
                
                
            
            
            
            
            
            
        
    


分析:在包含元素的Triggers集合中(在这里是Window.Triggers集合),使用EventTrigger.SourceName属性关联这些事件触发器,只要SourceName属性和为按钮设置的Name属性相匹配,触发器就会用到恰当的按钮上。还必须要问BeginStoryboard动作指定名称,这样其他触发器BeginStoryboardName属性指定这个名称,连接到相同的故事板,然后进行控制。

12、故事板事件。
WPF 动画系统_第7张图片
故事板事件
Completed 动画已经到达终点
CurrentGlobalSpeedInvalidated 速度发生了变化,或者动画被暂停、重新开始、停止或移到某个新的位置。
CurrentStateInvalidated 动画已经开始或结束。
CurrentTimeInvalidated 动画时钟已经向前移动了一个步长,正在更改动画。当动画开始、停止或结束时也会引发该事件。
RemoveRequested 动画正在被移除。

监视动画进度:

如果要监视动画,要用到Storyboard的一些事件。在这里使用的是CurrentTimeInvalidated事件,每次向前移动动画时钟都会引发该事件。当引发CurrentTimeInvalidated事件时,发送者是Clock对象(Color类位于System.Windows.Media.Animation名称空间中),可通过Clock对象检索当前时间。当前时间使用TimeSpan对象表示,并且可检索当前进度,当前进度使用0~1之间的数值表示。

后台代码:

就是在上面的例子中为故事板加一个CurrentTimeInvalidated事件,然后再界面中放一个label控件(用于显示时间)和ProgressBar(用于显示进度,最大值为1,最小值为0)控件。

private void Storyboard_CurrentTimeInvalidated(object sender, EventArgs e)
{
    Clock storyboardClock = (Clock)sender;
    if (storyboardClock.CurrentProgress == null)
    {
        lblTime.Content = "";
        progressBar1.Value = 0;
    }
    else
    {
        lblTime.Content = storyboardClock.CurrentTime.ToString();
        progressBar1.Value = (double)storyboardClock.CurrentProgress;
    }
}


13、动画缓动。
线性动画有一个缺点,通常让人觉得机械和不够自然。改进动画并创建更趋自然的动画的秘诀是改变变化速率。不是创建以固定不变的速率改变属性的动画,而是需要设计根据某种方式加速或减速的动画,实现更趋自然的动画的最简单方法是使用预置的缓动函数(EasingFunction)。EasyingFunction属性只能接受单个缓动函数对象,所以不能为同一个动画结合不同的缓动函数。

xaml代码


    
   

     

WPF 动画系统_第8张图片
14、缓动函数类。
在继续分析不同的缓动类之前,理解缓动函数的应用时机是很重要的。所有的缓动函数类都继承自EasingFunctionBase类,并且继承了EasingMode属性,EasingMode有三种值,分别是:EasyIn(在动画开始时应用缓动效果)、EasyOut(动画结束时应用缓动效果)和EasyInOut(在开始和结束时应用缓动动画)。当应用缓动函数时不会改变动画的持续时间。
WPF 动画系统_第9张图片
15、自定义缓动函数。
创建自定义缓动函数一般需要以下几个步骤:

a)、新建一个类,让其继承自EasingFunctionBase类。

b)、重写EaseInCore()方法和CreateInstanceCore()方法。

c)、定义依赖属性。

d)、引用。

后台代码(自定义类):

public class RandomJitterEase : EasingFunctionBase
{
    //声明一个Random类,用于声明随机数。
    Random rand = new Random();
    /// 
    /// 重写EaseCore方法。 
    /// 
    /// 
    /// 
    protected override double EaseInCore(double normalizedTime)
    {
        //几乎所有逻辑代码都在EaseInCore方法中运行。该方法接受一个规范化的时间值,本质上是表示动画进度从
        //0到1之间的值,当动画开始时,规范化的时间值是0,它从该点开始增加,直到在动画结束点达到1.
        //在动画运行期间,每次更新动画的值时,WPF都会调用EaseInCore方法,确切的调用频率取决于动画的帧率。
        if (normalizedTime == 1)
        {
            return 1;
        }
        else
        {
            return Math.Abs(normalizedTime - (double)rand.Next(0, 10) / (2010 - Jitter));
        }
    }

    protected override System.Windows.Freezable CreateInstanceCore()
    {
        return new RandomJitterEase();
    }

    //定义一个依赖属性。
    public static readonly DependencyProperty JitterProperty;

    //在静态方法中注册依赖属性。
    static RandomJitterEase()
    {
        JitterProperty = DependencyProperty.Register("Jitter", typeof(int), typeof(RandomJitterEase), new UIPropertyMetadata(1000), new ValidateValueCallback(ValidateJitter));
    }

    public int Jitter
    {
        get { return (int)GetValue(JitterProperty); }
        set { SetValue(JitterProperty, value); }
    }

    //此方法用于判断值。
    private static bool ValidateJitter(object value)
    {
        int jitterValue = (int)value;
        if (jitterValue <= 2000 && jitterValue >= 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

xaml代码:


    
    
        
        
            
                
                    
                        
                        
                            
                                
                                
                            
                        
                    
                
            
        
            
        
    
        
        
        

WPF 动画系统_第10张图片
16、WPF动画性能和帧率。
通常,为用户界面应用动画,只不过是创建并配置正确的动画和故事版对象。但在其他情况下,特别是同时发生多个动画时,可能更加需要关注性能。WPF试图保持以60帧/秒的速度进行动画,可以确保从开始到结束得到平滑流畅的动画。帧速率越低,会发生抖动现象。帧速率越高,占用的CPU也就越高。通过TimeLine.DesiredFrameRate属性进行调整。

xaml代码:

    
    
        
        
            
                
                    
                    
                        
                        
                    
                
            
        
        
    
    
        
            
            
                        
        
        
        
            
            
          
        
        
            
        
        
        
        
        
    

WPF 动画系统_第11张图片

转载自:https://www.cnblogs.com/xiezunxu/articles/8965848.html:

你可能感兴趣的:(WPF,动画,WPF,动画)