• Silverlight 简介 Part.5(动画)


           动画(animation)是 Silverlight 一项关键特性。它提供了炫目的视觉效果,这是基于服务器编程的框架无法仿效的(例如 ASP.NET)。在 Sileverlight 中动画可以实现很多效果(例如,鼠标经过时图标变大、logo 旋转、文本滚入视图等),也可以用来实现更宏大的商业设计和基于浏览器的游戏。

           动画是 Silverlight 模型的核心部分。这意味着你不需要以计时器和事件处理代码来实现它们,而是通过少数几个类来声明并配置它们

    动画基础知识

           Silverlight 动画是一个精简版的 WPF 动画系统。为了便于理解,需要了解以下关键规则:

    • Silverlight 执行以时间为基础的动画。因此,需要设定初始状态、最终状态、持续时间,而 Silverlight 计算出帧速。
    • Silverlight 使用基于属性的动画模型。这意味着一个动画只能做一件事:修改时间间隔的属性值。在很多方面,这是个很大的限制,但仅仅修改属性,也能创建出多得超乎想像的效果了。
    • 要赋予动画一个属性,就需要使用一个支持这种数据类型的动画类。例如,修改数据类型为 double 的属性,必须使用 DoubleAnimation 类。

           Silverlight 中的动画类比较少,只有有限的数据类型可以使用。目前,能用来修改动画属性的数据类型有 double、object、Color、Point

    定义动画

           创建动画是一个多步的过程。需要创建 3 个要素:执行动画的动画对象、管理动画的演示图板、启动演示图板的事件触发器

           Silverlight 有两种动画类,采用不同的变更属性值策略:

    • 线性插值:使用线性策略,属性值在动画的持续时间内逐渐变化,这种策略的例子包括 DoubleAnimationColorAnimationPointAnimation
    • 关键帧动画:使用关键帧策略,属性值可以从一个值跳跃到另一个值,或者结合跳跃和线性插值策略。这种策略的例子包括 DoubleAnimationUsingKeyFramesColorAnimationUsingKeyFramesPointAnimationUsingKeyFrames

           本文只介绍最常用的动画类:DoubleAnimation 类。它采用线性插值,在最小值和最大值之间选择双精度值。和所有动画类一样,被定义在 System.Windows.Media.Animation 命名空间中。

           虽然动画并不是元素,但仍然可用 XAML 标记定义。下面的标记创建一个 DoubleAnimation

    <DoubleAnimation From="160" to="300" Duration="0:0:5"></DoubleAnimation>

           这个动画持续5秒(Duration 属性格式:时:分:秒:毫秒),目标值在 160 – 300 之间变化。如果这个 DoubleAnimation 能以 Silverlight 默认的最高帧速运行,动画值每秒调整 60 次。

    StoryBoard 类

           演示图板用来管理动画的时间轴,可以用来组织多个动画,也可以用它来控制动画的播放、暂停、停止和改变它的位置。StoryBoard 类提供的最基本功能却是用 TargetPropertyTargetName 属性来指定特定的属性和特定的元素。换言之,演示图板是动画和要设置的动画属性之间的桥梁

           下面的标记定义一个演示图板,为名为 cmdGrow 的按钮的 Width 属性赋予 DoubleAnimation 类:

    <Storyboard x:Name="storyboard" Storyboard.TargetName="cmdGrow" 
                Storyboard.TargetProperty="Width">
        <DoubleAnimation From="160" To="300" Duration="0:0:5" ></DoubleAnimation>
    </Storyboard>

           Storyboard.TargetName 定义了要应用动画的目标元素,Storyboard.TargetProperty 定义了想在目标元素中改变的属性。如果要设置一个附加属性,例如 Canvas.Top,那么需要将整个属性名用括号括起来:

    <Storyboard x:Name="storyboard" Storyboard.TargetName="cmdGrow" 
                Storyboard.TargetProperty="(Canvas.Top)">
        <DoubleAnimation From="160" To="300" Duration="0:0:5" ></DoubleAnimation>
    </Storyboard>

           TargetName 和 TargetProperty 都属于附加属性,这意味直接在动画上应用这些属性也是可以的:

    <Storyboard x:Name="storyboard">
        <DoubleAnimation From="160" To="300" Duration="0:0:5" 
            Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width">
        </DoubleAnimation>
    </Storyboard>

           这种语法是较为常见的。因为它可以让你把多个动画放在一个演示图板里,并且允许每个动画拥有不同的元素和属性。尽管不能为多个动画在同一时间指定相同的属性,但可以(而且往往会)在同一时间为相同元素指定不同的属性。

           所有的 Silverlight 元素都有一个 Resources 属性,用以提供一个集合来存储各种对象。Resources 集合的主要目的是让你能够在 XAML 中定义那些不属于元素,因而也就不能被置于可见内容区域的对象。Resources 可以在代码中进行检索或者在标记中别的地方使用。对于那些按钮增长型动画来说,Resources 集合是一个方便的存储位置:

    <UserControl ...>
        <UserControl.Resources>
            <Storyboard x:Name="storyboard">
                <DoubleAnimation Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" 
                                 From="160" To="300" Duration="0:0:5" ></DoubleAnimation>
            </Storyboard>
        </UserControl.Resources>
     
        <Grid>
            <Button x:Name="cmdGrow" Width="160" Height="30" 
                    Content="This button grows" Click="cmdGrow_Click"></Button>
        </Grid>
    </UserControl>

           如果你想在启动动画之前通过程序调整它的属性,你也可以给 DoubleAnimation 添加一个名称,这样你可以在代码中访问到它。

           现在,只需要在事件处理程序中调用 StoryBoard 对象的方法即可。这些方法包括 Begin()、Stop()、Pause()、Resume()、Seek()。

    private void cmdGrow_Click(object sender, RoutedEventArgs e)
    {
        storyboard.Begin();
    }

    image image

    配置动画属性

           想要将动画这个功能发挥到极致,就必须认真研究 Animation 基类。这个类定义了所有动画类的属性:

    名    称

    描    述

    From 设置动画的初始值。很多时候不必设置,Silverlight 将使用元素的当前值。有时,你希望动画从当前值开始,而不是跳转到一个预设的 From 值。
    To 设置动画的结束值。
    By 使用 By 而不是 To 来创建一个持续增长的动画。给 By 设置一个值,这个值会和初始值累加在一起。之前的示例中,设置 By=10,去除 From 和 To 的设置,每次单击会使矩形按钮不断的增长
    Duration 运行的持续时间
    AutoReverse 如果设置为 true,动画结束之后会倒着运行一次回到初始值,持续时间会增加一倍
    RepeatBehavior 你可以设置重复运行动画的次数,或者使用 Forever 无休止的重复动画
    BeginTime 在动画开始之前设置一个延迟时间。如果你要将不同的动画进行同步,即同一时间启动所有动画,但是动画效果却要按序列运行,这非常有用
    SpeedRatio 增加或降低动画运行的速度。默认是 1 。设置成 5 将 5 倍加速完成。
    FillBehavior 决定动画结束时属性值的状态。通常,会保留属性值为动画结束时的状态(FillBehavior.HoldEnd),但也可选择让它回到初始值(FillBehavior.Stop

    交互式动画实例

           有时,你需要在程序中用代码创建动画的每一个细节,这种情况是相当普遍的。通过编程、配置以及启动动画并不困难。首先,创建动画以及演示图板对象并将动画添加到演示图板中。当这些动画结束的时候,还需要响应 Storyboard.Completed 事件来清理动画

           下面的例子演示了更贴近现实的动画的使用。一开始内容区域充满了形状不规则的矩形。单击矩形它会下降到画布的底部并同时改变颜色。可以连续快速的单击多个矩形以便同时运行多个动画。网页将使用多个演示图板,每个目前正在下降的矩形使用一个演示图板。当有需要时,这些演示图板就会被创建。

    image

           本例中的标记定义了一个包含有 Border 和一个 Canvas 的简单页面。它并不包含演示图板,因为这些细节需要在矩形被单击时动态创建:

    <UserControl x:Class="SilverlightApplication1.AnimationPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Width="500" Height="500" Loaded="Page_Loaded">
     
        <Border BorderBrush="SteelBlue" BorderThickness="1">
            <Canvas x:Name="canvas" Background="AliceBlue"></Canvas>
        </Border>
    </UserControl>

           这个画布并不包含任何其他元素,因为这里将动态生成矩形。当画布被加载时,它在随机的位置创建 20 个大小随机的矩形。这些矩形采用相同的 MouseLeftButtonDown 事件处理程序:

    private void Page_Loaded(object sender, RoutedEventArgs e)
    {
        // Generate some rectangles.
        Random random = new Random();
        for (int i = 0; i < 20; i++)
        {
            Rectangle rect = new Rectangle();
            rect.Fill = new SolidColorBrush(Colors.Red);
     
            // Size and place it randomly.
            rect.Width = random.Next(10, 40);
            rect.Height = random.Next(10, 40);
            Canvas.SetTop(rect, random.Next((int)(this.Height - rect.Height)));
            Canvas.SetLeft(rect, random.Next((int)(this.Width - rect.Width)));
     
            // Handle clicks.
            rect.MouseLeftButtonDown += new MouseButtonEventHandler(rect_MouseLeftButtonDown);
     
            // Add it to the Canvas
            canvas.Children.Add(rect);
        }
    }

           当一个矩形被单击时,需要创建新的演示图板及相应的动画。在本例中,你需要两个动画分别用来修改矩形的属性。DoubleAnimation 用来改变 Canvas.Top 属性使得矩形可以下降;ColorAnimation 用来混合矩形的颜色。

           这个演示图板会被加入到集合中,这样你可以轻松跟踪当前运行的演示图板以及相应的动画元素。通过一个事件处理程序,代码可以在上一个动画结束时接收到通知,然后启动这个动画。

    void rect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Rectangle rect = sender as Rectangle;
     
        // Create the storyboard for the rectangle
        Storyboard storyboard = new Storyboard();
     
        // Create the animation for moving the rectangle.
        DoubleAnimation fallingAnimation = new DoubleAnimation();
        Storyboard.SetTarget(fallingAnimation, rect);
        Storyboard.SetTargetProperty(fallingAnimation, new PropertyPath("(Canvas.Top)"));
        fallingAnimation.To = this.Height - rect.Height;
        fallingAnimation.Duration = TimeSpan.FromSeconds(2);
        storyboard.Children.Add(fallingAnimation);
     
        // Create the animation for changing the rectangle's color.
        ColorAnimation colorAnimation = new ColorAnimation();
        Storyboard.SetTarget(colorAnimation, rect.Fill);
        Storyboard.SetTargetProperty(colorAnimation, new PropertyPath("Color"));
        colorAnimation.To = Colors.Blue;
        colorAnimation.Duration = fallingAnimation.Duration;
        storyboard.Children.Add(colorAnimation);
     
        // Track the rectangle.
        animatedShapes.Add(storyboard, rect);
     
        // React when the storyboard is finished.
        storyboard.Completed += new EventHandler(storyboard_Completed);
     
        // Start the storyboard.
        storyboard.Begin();
    }

           当演示图板结束时,就到了清理的时间。下面是用来完成这一任务的最简单的代码:

    void storyboard_Completed(object sender, EventArgs e)
    {
        Storyboard storyboard = sender as Storyboard;
        storyboard.Stop();

        animatedShapes.Remove(storyboard);
    }

           然而有一个问题,动画实际上并不真正改变这些属性的值,只不过是临时覆盖它,只是你不会注意到这个事实,因为完成的动画并没有真正停止。相反,当一个动画结束时,它的属性会继续保持在动画结束时的状态。这意味着,在演示图板结束之后,完成了动画的矩形仍会停留在页面的底部,并且仍然是蓝色。

           问题是,当动态创建演示图板时,可能存在相当多的演示图板在同一个时间执行的情况。为了确保良好的性能,在动画结束时明确终止演示图板就变得非常重要。就像上述代码所作的那样

           然而,新问题又来了。终止动画会使得动画的属性回到初始值。在这个例子中,意味着每一次终止一个下降的矩形,它将会跳转到原来的位置,恢复原来的红色。解决办法是检索矩形的 Canvas.Top 属性的当前值(这就是声明 Dictionary 结合的原因,可以获取到矩形元素的引用),然后终止动画,并将这个值重新赋予这个矩形:

    void storyboard_Completed(object sender, EventArgs e)
    {
        // Stop the animation but keep the new position
        Storyboard storyboard = sender as Storyboard;
        Rectangle rect = animatedShapes[storyboard];
        rect.Fill = new SolidColorBrush(Colors.Blue);
        double newTop = Canvas.GetTop(rect);
        storyboard.Stop();
        Canvas.SetTop(rect, newTop);
     
        // Remove it from the tracking collection.
        animatedShapes.Remove(storyboard);
    }

    image       

    变换

           Silverlight 动画是通过修改属性值工作的。元素有多个属性值可以修改,这非常有用。设置 Canvas.Top、Cnavas.Left 来将一个元素四处移动。改变 Opactity 可以使得元素淡入淡出

           更令人兴奋的变更,例如旋转。秘诀就是变换。变换是一个对象,通过切换坐标系来更改一个形状或者其他元素的绘制方向。在 Silverlight 用户界面中,使用变换来伸展、旋转、扭曲来操控形状、图像和文字

    Silverlight 支持的变换(类)

    名称

    描述

    重要属性

    TranslateTransform 平移坐标系统。适用于在不同位置画出相同的形状 X、Y
    RotateTransform 旋转坐标系统。围绕你选择的中心点进行旋转 Angle、CenterX、CenterY
    ScaleTransform 拉伸坐标系统。拉伸或压缩形状 ScaleX(Y)、CenterX(Y)
    SkewTransform 倾斜坐标系统。以一定度数扭曲,例如,将正方形变成一个平行四边形 AngleX、AngleY
    CenterX、CenterY
    MatrixTransform 改变坐标系统。用你提供的矩阵进行矩阵相乘 Matrix
    TransformGroup 组合多种变换方式,使得所有方式可以一起使用。你设置的变换的排列顺序非常重要。  

           从技术上讲,所有的变换都采用矩阵数学的方式来改变形状的坐标。然而,使用预先定义好的变换(TranslateTransform、RotateTransform、ScaleTransform、SkewTransform),将会比用 MatrixTransform 并试图为想要实现的操作找到正确的矩阵简单很多

           当使用 TransformGroup 执行一系列变换时,Silverlight 会将你的变换融合成一个单一的 MatrixTransform 确保得到最佳性能。

    1. 使用变换

           要变换一个元素时,需要设置想要使用的变换对象的 RenderTransform 属性。根据要使用的变换类型,你需要为其配置不同的属性(如上表)。例如,将一个按钮顺时针旋转 25 度:

    <Button Content="A Button">
        <Button.RenderTransform>
            <RotateTransform Angle="25"></RotateTransform>
        </Button.RenderTransform>
    </Button>

           如果用这种方式旋转一个元素,就是围绕元素的起点(左上角)开始旋转。如果要围绕不同的点来旋转一个形状,可以使用方便的 RenderTransformOrigin 属性。这个属性使用相对坐标系统来设置中心点,中心点的值介于 0 和 1 之间。换言之,点(0,0)被指定为左上角,点(1,1)则是右下角。(如果这个元素不是正方形,坐标系统就会相应地拉伸)

           在 RenderTransformOrigin 的帮助下,你可以使用如下标记围绕其中心点旋转任何元素:

    <Button Content="One" RenderTransformOrigin="0.5,0.5">
        <Button.RenderTransform>
            <RotateTransform Angle="25"></RotateTransform>
        </Button.RenderTransform>
    </Button>

           这段标记能达到我们想要的效果,因为无论这个形状大小是多少,点(0.5,0.5)都表示它的中心点。你也可也用 RenderTransformOrigin 属性指定形状边界之外的一个点,可以使用大于 1 或者小于 0 的值,例如,以一个非常遥远的点为圆心(5,5)。

    2. 动画变换

           要想在动画中使用变换,第一步是定义变换,动画可以改变现有的变换但是不能创建新的变换。例如下面示例:

    <Button x:Name="cmd" Content="A Button" RenderTransformOrigin="0.5,0.5">
        <Button.RenderTransform>
            <RotateTransform x:Name="buttonTransform"></RotateTransform>
        </Button.RenderTransform>
    </Button>

           现在这里有一个动画,当鼠标经过一个按钮时,按钮将旋转。这个动画作用于 Button.RotateTransform 对象,并且使用了 Angle 属性:

    <Storyboard x:Name="rotateStoryboard">
        <DoubleAnimation Storyboard.TargetName="buttonTransform"
            Storyboard.TargetProperty="Angle" To="360" Duration="0:0:0.8"
            RepeatBehavior="Forever"></DoubleAnimation>
    </Storyboard>

           这个按钮每 0.8 秒旋转一次,并且会持续不断进行旋转。旋转中的按钮仍然完全可用。例如,你可以单击它并处理 Click 事件。

    private void cmd_MouseEnter(object sender, MouseEventArgs e)
    {
        rotateStoryboard.Begin();
    }

           要停止旋转,可以响应 MouseLeave 事件。这样的话,虽然可以停止执行旋转的演示图板,但这会导致按钮一下子跳转回初始方向。

  • 相关阅读:
    centos : 创建交换分区
    用法记录
    mysql日志清理
    mysql 通过查看mysql 配置参数、状态来优化你的mysql
    [WPF 自定义控件]Window(窗体)的UI元素及行为
    [WPF 自定义控件]为Form和自定义Window添加FunctionBar
    [WPF 自定义控件]让Form在加载后自动获得焦点
    [WPF 自定义控件]简单的表单布局控件
    [WPF 自定义控件]以Button为例谈谈如何模仿Aero2主题
    [WPF 自定义控件]自定义控件的代码如何与ControlTemplate交互
  • 原文地址:https://www.cnblogs.com/SkySoot/p/2989247.html
Copyright © 2020-2023  润新知