WPF 有趣的动画效果
这一次我要呈上一个简单的文章,关于给你的WPF apps添加漂亮的光线动画,但是我对动画这东西可能有点入迷了。
实际上,我对动画如此的入迷,以至于我最后做了之前从未打算做的东西,就是使用一些非常有用的.NET代码,渐变填充生成背景动画。让我先给你看一些最终效果吧。
WPF和元素定位
然而,在我们开始之前,我们需要考虑一件事情。这件事让我也有点原地转圈的感觉。
似乎当你使用WPF创建任何闭环形状时,你不能设置它的X和Y坐标。好吧,至少你不能在一般的WPF窗体(像VS开箱即用的形状)上。
这一点上,我要谢谢我的好朋友(以及WPF各种大神)Gavin Lanata,他帮我解释说,如果要在代码中以我想要的方式定位,就不得不将窗口的根布局从grid变为canvas。这是很令人沮丧的,如此简单的东西(并且是大多开发人员会考虑寻找的东西)在WPF中却不被认为是绘制形状的要求。我跑题了,现在我们什么也做不了。
让我们开始吧
打开Visual Studio,开始新的WPF应用程序项目,命名为WpfAnimationTest。你可以使用Blend,但是因为我们大多数要输入代码,Blend可能有点过度了。
一旦你的模板加载完毕,请修改你的“MainWindow.xaml”文件,看起来像这样。
<Window x:Class="WpfAnimationTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF Animation Testing" Height="600" Width="800" WindowStartupLocation="CenterScreen"> <Canvas x:Name="Root" Background="Black"> </Canvas> </Window>你会看到,除了将背景变为黑色,我们改变了默认的grid为canvas,并且设置了窗体大小和标题。改变的也不多。不像大多说WPF/XAML项目,这里我们画的大部分用代码实现。
使用这个记录,你可以轻易使用声明的XAML,复制本文中的所有东西,但是会有大量重复渐变、渐变点和其他需要资源的东西。通过使用这里的代码方法,我们是用的任何东西在超出范围后都可以处理掉;而且更重要的是,它是可重用代码。
首先是一点儿理论
首先是一点儿理论
如果你了解过XAML,你将可能知道WPF中所有东西都可以成为动画。颜色,位置,大小,填充这些可以使用时间线和故事板可以很容易变成动画。
你使用许多可用动画时间线类型中的一种创建你的动画顺序,通常新建对象,然后设置开始值、终止值,以及动画运行时间长度。然后在将它们附加到故事板并启动运行之前,附加这些动画时间线到你想要它们控制的UI元素的属性上。
然而,有件事我没有意识到,一个彩色渐变点位置也可以做成动画。当你在WPF中创建颜色渐变时,你使用一系列对象“渐变点”创建了它们。
如果你曾经使用过PhotoShop之类的图像处理软件,并且使用小方形颜色标记器在颜色应该改变的地方标记填充位置,你已经使用了相似的概念。例如,如果你想要在中间使用从红到蓝颜色渐变,然后变绿,你可能在0%处创建红色点,在50%创建蓝色,100%处创建绿色。WPF图画引擎然后在所有颜色间填充,这样你就得到从一个颜色到下一个的平滑过渡。
在大多数WPF中大多数测量使用所谓的本地坐标系统。这意味着你的窗体上,可能宽度有比如800像素,从0%到100%范围使用0到1来代表。设置渐变时,这可能意味着0像素在0.0或0%,400像素在0.5或50%,800像素在1.0或100%,所有你的颜色点位置都是这样指定的。
我们试一些代码吧
打开主要窗口XAML代码。假设你已经如之前提到的修改了canvas,你应该添加如下代码到MainWindow构造器中。
public MainWindow() { InitializeComponent(); Rectangle myRect = new Rectangle { Width = 300, Height = 100, Stroke = Brushes.White, StrokeThickness = 1 }; Root.Children.Add(myRect); Canvas.SetLeft(myRect, 100); Canvas.SetTop(myRect, 100); }当你按下F5,你应该能看到黑色背景上白色矩形,距离每个角都是100像素,大小300像素*100像素。需要Canvas SetLeft和SetTop调用,是因为微软决定允许绘制闭环形状的任何人来决定形状绘制的位置时没有用处的。
如果你也增加了填充参数:
public MainWindow() { InitializeComponent(); Rectangle myRect = new Rectangle { Width = 300, Height = 100, Stroke = Brushes.White, StrokeThickness = 1, Fill=Brushes.Red }; Root.Children.Add(myRect); Canvas.SetLeft(myRect, 100); Canvas.SetTop(myRect, 100); }你也可以设置矩形全局的实心填充颜色。然而,实心颜色有点无趣。我们将修改成更加有趣的东西。
首先,让我们通过将它在自身的函数中包装起来,然后也创建数据对象传送参数过去。我们将添加所有需要的参数到数据对象,并且我将解释我们遇到的每个对象。
添加新类到你的项目,命名为BarDescription。输入如下代码:
namespace WpfAnimationTest { public class BarDescriptor { public int RectangleX { get; set; } public int RectangleY { get; set; } public int RectangleWidth { get; set; } public int RectangleHeight { get; set; } public int AnimationTimeInSeconds { get; set; } // 0.0 to 1.0 public float BarBaseRedLevel { get; set; } public float BarBaseGreenLevel { get; set; } public float BarBaseBlueLevel { get; set; } public float GradientStartX { get; set; } public float GradientStartY { get; set; } public float GradientEndX { get; set; } public float GradientEndY { get; set; } } }确保按照你的需要修改了命名空间。
然后,打开MainWindow.xaml.cs(或者你任意命名的主窗口后台代码),然后确保输入一下代码:
using System; using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace WpfAnimationTest { public partial class MainWindow { private Rectangle _testRect; public MainWindow() { InitializeComponent(); Loaded += MainWindowLoaded; } private void MainWindowLoaded(object sender, RoutedEventArgs e) { BarDescriptor barOne = new BarDescriptor { RectangleX = 100, RectangleY = 100, RectangleWidth = 200, RectangleHeight = 200, AnimationTimeInSeconds = 0, BarBaseRedLevel = 0, BarBaseGreenLevel = 0, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0, GradientEndX = 0, GradientEndY = 0 }; CreateRectangleAnimatedRectangle(barOne); } private void CreateRectangleAnimatedRectangle(BarDescriptor inputParameters) { _testRect = new Rectangle { Width = inputParameters.RectangleWidth, Height = inputParameters.RectangleHeight, Stroke = Brushes.White, StrokeThickness = 1, }; Root.Children.Add(_testRect); Canvas.SetLeft(_testRect, inputParameters.RectangleX); Canvas.SetTop(_testRect, inputParameters.RectangleY); } } }再一次,确保输入正确的命名空间。正如之前的例子,运行时你应该又看到白色矩形,但是现在你也应该能够轻松添加新矩形,通过创建新的“BarDescriptor”对象,并设置相应参数。
然而,现在假设你设置主窗口大小和我的相同(800*600),设置barOne属性如下:
BarDescriptor barOne = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 0, BarBaseRedLevel = 0, BarBaseGreenLevel = 0, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0, GradientEndX = 0, GradientEndY = 0 };这样会创建和主窗口同样大小的矩形。
添加渐变