WPF之小动画二
上一篇文章简单介绍了动画的定义方法和一些控制动画的方法,并没有涉及复杂属性的动画处理方式,本文将继续动画的其它方面的使用。
写在前面(对于一些动画操作时候的建议):
1.如果希望某个元素从显示到消失,或者从消失到显示,使用Visibility属性是无效的,因为此属性没有一个动画的过程,所以使用Opacity控制透明度进行操作;
2.如果要修改元素的位置则可以使用Canvas.Left或者Canvas.Top设置是RenderTransform(下文会涉及);
3.可以使用ColorAnimation修改元素的Brush,如果是比较复杂的aBrush,则可以使用DoubleAnimation来修改OffSet偏移量。
动画和Transforms:
Transforms可以对元素进行水平和垂直移动、可以使元素旋转、也可以使元素放大缩小以及进行使元素扭曲,通常在动画中会修改各种Transform的属性以达到动画的效果。
<Window x:Class="WpfApplication3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter>
<Setter Property="Padding" Value="20,15"></Setter>
<Setter Property="Margin" Value="2"></Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform></RotateTransform>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
To="360" Duration="0:0:0.8" RepeatBehavior="Forever"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
Duration="0:0:0.2"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Margin="5">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
<Button>Four</Button>
<TextBlock Name="lbl" Margin="5"></TextBlock>
</StackPanel>
</Window>
效果图为窗体上有四个按钮,鼠标悬浮到按钮上,按钮则进行360度的持续旋转,当鼠标离开,则恢复原状。
代码解析:上述代码的语法在上一篇博客中已经介绍过,通过Style和Trigger以及Animation进行操作,唯一区别就是在上述代码中使用了RenderTransform。可以看到在样式中给Button添加了RenderTransform属性,此处使用的是RotateTransform,也就是旋转变换。在MouseEnter时候开始执行动画,动画的属性为RenderTransform.Angle即旋转的角度,To就是360度,并且动画吃持续性的。在MouseLeave时候开始执行恢复原状的动画,如果From和To都不设置则将To默认为原有的值。(之所以可以直接使用RenderTransform.Angle是因为当前我们的RenderTransform只有一个变换对象,所以可以直接使用的,如果有多个变换对象,则要看下文喽)
Tips:LayoutTransform和RenderTransform的区别
与 RenderTransform相比, LayoutTransform 将影响布局的结果。 设置转换提供缩放和旋转的强大功能。 但是, LayoutTransform 忽略 TranslateTransform 操作。 这是因为, FrameworkElement 的子元素的布局系统行为自动更正对缩放的或旋转的元素的位置的所有偏移量父元素的布局和坐标系中。 LayoutTransform 可能导致应用程序性能变差,如果调用它在不需要布局系统执行全面处理过程的方案。 将 LayoutTransform 于 Panel时的 Children 集合,它将触发布局系统新通过和强制屏幕上的所有对象。重新度量和重新排列。 如果要更新完整的应用程序 用户界面 (UI),此功能可能完全符合您的需要。 但是,因此,如果不需要完整布局处理过程,请使用 RenderTransform 属性,不会调用布局系统,并且,通常是此方案的更好的选择。 |
理论说多了都是泪,看看LayoutTransform的例子:
<Style TargetType="{x:Type Button}">
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter>
<Setter Property="Padding" Value="20,15"></Setter>
<Setter Property="Margin" Value="2"></Setter>
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform></RotateTransform>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="LayoutTransform.Angle"
To="360" Duration="0:0:0.8" RepeatBehavior="Forever"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="LayoutTransform.Angle"
Duration="0:0:0.2"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
如你所见,没有怎么改动,只是把RenderTransform的地方都改为了LayoutTransform(话说楼主也是因为Property写的是LayoutTransform,而在动画中使用的是RenderTransform,却一直报错)。运行程序,你会发现按钮在旋转的时候整个布局都是弹跳(比喻),其实就是动态更改布局。
多个Transform(TransformGroup):
顾名思义,多个Transform,也就意味着可以同时向元素应用多个Transform,也可以在动画中对其,进行修改。下面的例子为,默认情况下Image倾斜角度为50,并且缩放了0.5倍,同时Image的Opacity透明度为0.5,在窗口进行最大化的时候使Image角度为0,然后大小正常,透明度为1。
<Image Height="300" Width="300" Source="Desert.jpg" Opacity="0.5" x:Name="imgTransform">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"></ScaleTransform>
<RotateTransform Angle="50"></RotateTransform>
</TransformGroup>
</Image.RenderTransform>
</Image>
动画资源
<Window.Resources>
<Storyboard x:Key="sbTransform">
<DoubleAnimation Storyboard.TargetName="imgTransform" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" To="1" Duration="0:0:1"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="imgTransform" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" To="1" Duration="0:0:1"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="imgTransform" Storyboard.TargetProperty="RenderTransform.Children[1].Angle" To="0" Duration="0:0:1"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="imgTransform" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:1"></DoubleAnimation>
</Storyboard>
</Window.Resources>
解释:在Image中主要是对其RenderTransform使用了TransformGroup,表示可以放置多个Transform,在此是一个缩放的ScaleTransform和一个旋转的RotateTransform。在动画中使用了四个DoubleAnimation,前三个为Transform。在TargetProperty中使用的属性是不是觉得很奇怪,那你还记不记得我们第一个例子中是直接使用RenderTransform.属性的呢,区别就是第一个例子我们只有一个Transform,而这里我们有两个(是一个集合哦),所以我们需要通过RenderTransform的Children属性根据索引得到对应的Transform。在这里0代表的就是ScaleTransform,1就是RotateTransform,所以可以分别设置它们的属性,最后一个Animation没什么说的,就是修改透明度。
开始动画:
private void Window_SizeChanged_1(object sender, SizeChangedEventArgs e)
{
if (WindowState== System.Windows.WindowState.Maximized)
{
Storyboard storyboard = this.Resources["sbTransform"] as Storyboard;
storyboard.Begin();
}
}
在窗口的SizeChange中,判断如果为最大化,则开始动画。
动画和颜色(Brush):
颜色:
<Rectangle Name="rectTest" Fill="Green" Height="100" Width="100" >
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="Red" Storyboard.TargetProperty="Fill.Color" Duration="0:0:1"></ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
一个Rectangle矩形,默认为绿色,点击之后变为红色。在这里使用的是ColorAnimation,表示颜色动画,这个不是重点,重点是Property的设置,由于颜色(不管是Rectangle的Fill还是其它元素的Background类型都是Brush)的类型都是Brush,而Brush是无法进行设置的,所以需要给其Color进行设置,也就看到了上述的语法。
Brush:
上述例子修改的是某一个元素的颜色,现在开始试着修改Brush这样的类型。
动画修改偏移量:
<Rectangle Name="rectTest" Height="100" Width="100" >
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Offset="0" Color="Red"></GradientStop>
<GradientStop Offset="1" Color="Green"></GradientStop>
</LinearGradientBrush>
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="0.2" Storyboard.TargetProperty="Fill.GradientStops[0].Offset" Duration="0:0:1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
此例子关键点在于Property,Fill.GradientStops表示画刷的整个渐变点的集合,然后通过索引确定某一个渐变项,然后修改偏移量。
动画修改渐变项的颜色:
<Rectangle Name="rectTest" Height="100" Width="100" >
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Offset="0" Color="Red"></GradientStop>
<GradientStop Offset="1" Color="Green"></GradientStop>
</LinearGradientBrush>
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="Yellow" Storyboard.TargetProperty="Fill.GradientStops[0].Color" Duration="0:0:1"></ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
此例子关键点和上述基本一致,唯一区别是使用了ColorAnimation,修改的是Color属性。
动画修改画刷的属性和渐变项的颜色:
<Rectangle Name="rectTest" Height="100" Width="100" >
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="0.5,0.5">
<GradientStop Offset="0" Color="Red"></GradientStop>
<GradientStop Offset="1" Color="Green"></GradientStop>
</RadialGradientBrush>
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<PointAnimation To="0.7,0.5" Storyboard.TargetProperty="Fill.GradientOrigin" Duration="0:0:1"></PointAnimation>
<ColorAnimation To="Yellow" Storyboard.TargetProperty="Fill.GradientStops[0].Color" Duration="0:0:1"></ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
此例子关键点在第一个动画,Property修改的是Brush的Gradientorigin属性而并非见渐变项的,从上述各种代码可以看到,如果元素的颜色属性就是一个Bursh,那么可以使用“颜色属性.Brush的属性"进行访问。
动画和着色器(BlurEffect):
<Button Content="A Button">
<Button.Effect>
<BlurEffect Radius="10"></BlurEffect>
</Button.Effect>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Effect.Radius" To="0" Duration="0:0:0.4"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Effect.Radius" To="10" Duration="0:0:0.2"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
一个Button,添加了BlurEffect用于模糊,默认模糊为10像素,当鼠标悬浮时候变为正常,鼠标离开变为10想速度模糊,没有难点,和之前的大致一样,例子旨在说明动画可以应用到大部分你想改变的属性上。
关键帧动画(本来是蛮不错的东西,不过本人之前的Silverlight中已经有提到,大家可以移步到此,戳我):
轨迹动画(Path-Animation):
轨迹动画,顾名思义,根据某一段轨迹进行运动的过程,当然也就少不了三元素,要运动的Element,轨迹Path,动画。
<Window.Resources>
<PathGeometry x:Key="path">
<PathFigure IsClosed="True">
<ArcSegment Point="100,200" Size="15,10" SweepDirection="Clockwise"></ArcSegment>
<ArcSegment Point="400,50" Size="5,5" ></ArcSegment>
</PathFigure>
</PathGeometry>
<Storyboard x:Key="sbTest">
<DoubleAnimationUsingPath
Storyboard.TargetName="image"
Storyboard.TargetProperty="(Canvas.Left)"
PathGeometry="{StaticResource path}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="X"/>
<DoubleAnimationUsingPath
Storyboard.TargetName="image"
Storyboard.TargetProperty="(Canvas.Top)"
PathGeometry="{StaticResource path}"
Duration="0:0:5"
RepeatBehavior="Forever"
Source="Y"/>
</Storyboard>
</Window.Resources>
上述代码中放置了一个Path,表示运动的轨迹(轨迹的语法有点DT,所以大家还是去找MSDN吧)。一个动画,动画的类型是前所没有使用过的DoubleAnimationUsingPath,表示使用Path执行的Double动画。TargetName下文会出现就是一图片(其实是使用DrawingImage绘制的),Property又好奇怪,其实这个就是附加属性的语法(关于这个大家再移步一下,戳我)。接下来重要的出现了,PathGeometry和Source,没错前者就是要运动的轨迹,果断把我们的Path丢给它;Source又是嘛意思呢,根据MS的解释就是在运动过程中的输出,说白了就是这个值到底是X还是Y还是Angle,因为Path是一系列de坐标组成的,所以你懂得。在两个动画中分别设置Canvas.Left和Canvas.Top,Left当然应该使用X,而Top也顺其自然的使用Y了。
看到了吧,小图片根据这个轨迹在蹭蹭蹭的跑呢。
好了,此次介绍就到这里了,下一篇会有亮瞎眼睛的东西哦,敬请期待。
WPF之小动画二的更多相关文章
- jquery实现一些小动画二
jquery实现一些小动画二 jquery实现拖拽功能 <!DOCTYPE html> <html lang="en"> <head> < ...
- WPF之小动画三
如果前两篇的博客太为普通,那么接下来的内容将让你动画实在是太厉害了.本文将会介绍两个关于纯手工实现动画的形式,当然动画效果就不用我多说了. 基于帧的动画: 此处的帧并不是之前介绍的Animation这 ...
- WPF之小动画一
定义动画: 直接使用Element进行BeginAnimation DoubleAnimation animation = new DoubleAnimation(); animation.By = ...
- WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...
- 如何制作网页小动画?——gif or png
一.场景与动画 为了拉动网站氛围,或者吸引用户浏览焦点,需要使用一些小动画.这种动画不是(gif)单纯的重复,而是需要需要一些控制和交互,比如在动画完成后打开一个对话框.动画有几个基本要素(时间控制, ...
- WPF学习拾遗(二)TextBlock换行
原文:WPF学习拾遗(二)TextBlock换行 下午在帮组里的同事解决一个小问题,为了以后方便,把就把它收集一下吧. 新建一个TextBlock作为最基础的一个控件,他所携带的功能相对于其他的控件要 ...
- WPF命中测试示例(二)——几何区域命中测试
原文:WPF命中测试示例(二)--几何区域命中测试 接续上次的命中测试,这次来做几何区域测试示例. 示例 首先新建一个WPF项目,在主界面中拖入一个按钮控件,并修改代码中的以下高亮位置: 当前设计视图 ...
- 【WPF学习笔记】[转]周银辉之WPF中的动画 && 晓风影天之wpf动画——new PropertyPath属性链
(一)WPF中的动画 动画无疑是WPF中最吸引人的特色之一,其可以像Flash一样平滑地播放并与程序逻辑进行很好的交互.这里我们讨论一下故事板. 在WPF中我们采用Storyboard(故事板)的方式 ...
- WPF 有趣的动画效果
WPF 有趣的动画效果 这一次我要呈上一个简单的文章,关于给你的WPF apps加入美丽的光线动画,可是我对动画这东西可能有点入迷了. 实际上.我对动画如此的入迷,以至 ...
随机推荐
- Smarty模板引擎技术
Smarty模板引擎技术 什么是模板引擎? 什么是Smarty模板引擎? 为何选择Smarty模板引擎? 如何使用Smarty模板引擎? 一.历史背景 场景一:回顾之前编写PHP项目的方式 //链接数 ...
- Linux 进行反编译 或者 汇编
Linux 进行反编译 或者 汇编 一.需要的工具 1.objdump 2. 3.
- mysql 导出表结构
mysql导出数据库各表结构,很简单只要一条命令即可: mysqldump -uxxx -d databasename [,table] > xxx.sql mysqldump中-d参数即为只导 ...
- android源码-安卓源码-Android源码下载-安卓游戏源码
android源码 高仿精仿金山手机卫士应用源码V1.2 高仿精仿金山手机卫士应用源码,该应用的级别实现了金山卫士的级别功能了,可以说跟现实中我们使用的金山卫士应用的功能几乎差不 人气:9286 ...
- Linux C 程序 预处理,结构体(13)
C语言预处理,结构体 C语言预处理命令1.宏定义 1.无参数宏 #define 标识符 字符串 #代表本行是编译预处理命名 习惯上,宏定义大写 代替一个字符串,介绍重复书写某个字符串的工作量 有意义的 ...
- spring-cloud-feign案例
主要依赖 <dependencyManagement> <dependencies> <dependency> <groupId>org.springf ...
- Python通过Manager方式实现多个无关联进程共享数据
Python官方文档 Python实现多进程间通信的方式有很多种,例如队列,管道等. 但是这些方式只适用于多个进程都是源于同一个父进程的情况. 如果多个进程不是源于同一个父进程,只能用共享内存,信号量 ...
- android.support.v7.app.AppCompatActivity
1.Android Studio (api 23) 新建项目的时候 Activity public class MainActivity extends AppCompatActivity 2.系统默 ...
- GridView ItemCommand
GridView ItemCommand中取某行某列的值方法,这里提供两个常用的: 一.用CommandArgument属性取值页面如下: <asp:TemplateColumn HeaderT ...
- 【BZOJ 2878】 [Noi2012]迷失游乐园
Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环( ...