WPF:(四)常见的动画及案例
⼀. 基本概念
WPF的⼀个特点就是⽀持动画,我们可以⾮常容易的实现漂亮⼤⽅的界⾯。⾸先,我们来复习⼀下动画的基本概念。计算机中的动画⼀般是定格动画,也称之为逐帧动画,它通过每帧不同的图像连续播放,从⽽欺骗眼和脑产⽣动画效果。
⼆. WPF的动画的实现
(1)简洁
这个是⾮常明显的,WPF的动画的代码⾮常容易理解,Timer的版本则要难懂得多。当然,我们也可以通过封装,使得⽤Timer也能⽤类似的API实现动画。但动画的API并不是仅仅这么⼀点,要把整个动画框架的API都封装也没有那么容易。
(2)和XAML⽆缝集成
这个就是WPF的独有技术了,得益于XAML强⼤的表述能⼒,我们可以写出⾮常强⼤且容易维护的动画。这点WinFom的Timer版本是⽆法做到的。
(3)流畅性
如果将这两种实现⽅式⼀起跑起来⽐较⼀下就会发现,Timer实现的版本明显要卡顿,并且并没有精准的按照我们设计的那样运动。具体原因为:
(4)Timer精度的问题:
由于是改UI控件的属性(按钮的宽度),因此必须在UI线程上进⾏,因此DispatcherTimer操作与其他操作⼀样需要放置到Dispatcher队列中,它并不保证恰好在改时间间隔中。它并不适合动画这种间隔很短的计时。
(5)帧率的问题:
逐帧动画的流畅性⼀般取决于每秒更新的帧数,也就是常说的帧率。⼈眼睛上限是70帧,⽽我这⾥代码中的Timer的固定了为20帧,因此是能明显感觉到卡顿的。⽽WPF的动画则不然,从它的API中可以看到,它是没有帧率的设置的。实际上,它是根据计算机的性能和当前进程的繁忙程度尽可能增⼤帧率的,因此WPF的动画是远⼤于20帧的,因此要流畅得多。
那么,是否只要修改参数,加⼤Timer的版本的帧率,也可以实现同样流畅的动画呢? 试了⼀下,就算修改参数,也是⽆法达到WPF版本的流畅程度的。我认为原因主要有如下两点,
DispatcherTimer精度不够,⽆法实现⼤帧率下准确刷新。
通过简单的设置参数很难像WPF那样帧率根据计算机的性能和当前进程的繁忙程度智能匹配帧率。帧率设置过低,动画不流畅,设置过⼤,处理不过来仍然不流畅。并且UI线程的忙碌程度是会动态变化的,帧率也需要相应调整,这些都⽆法通过Timer来简单的处理。
三. From/To/By 动画
这种过渡动画⼀般成为From/To/By 动画,是因为它们是通过From、To、By三个属性来决定了⽬标属性的起始值和结束值。⾸先我们来看下这三个属性代表的意义:
(1). From: 起始值,在动画开始的时候将⽬标属性设置为该值
(2). To: 结束值,动画结束是⽬标属性为改值
(3). By: 偏移值:动画结束的时候⽬标属性为"初始值+偏移值"
很明显,To和By的效果是有可能冲突的。实际上,这三个属性都是可选设置的,并且在设置了To和By的时候,是会忽略By属性的。下⾯我再通过⼀些简单的场景介绍⼀下这三个属性如何组合使⽤。
属性具有动画功能的要求
(1). 它必须是依赖项属性。
(2). 它必须属于继承⾃ DependencyObject 并实现 IAnimatable 接⼝的类。
(3). 必须存在可⽤的兼容动画类型.
四. 简单的动画实现(使元素从显⽰到透明)
(1) 先添加⼀个元素
<Canvas>
<Border Name="Bd" Width="100" Height="100" Background="Cyan" Canvas.Left="200" Canvas.Top="120"></Border>
</Canvas>
(2)创建 DoubleAnimation(浮点动画)
使元素逐渐进⼊视野并逐渐从视野中消失的⼀种⽅法是对其 Opacity 属性进⾏动画处理。由于 Opacity 属性的类型是 Double,因此需要⼀个产⽣双精度值的动画。DoubleAnimation 就是这样的⼀个动画。
DoubleAnimation 创建两个双精度值之间的过渡。若要指定其起始值,可设置其From属性。若要指定其终⽌值,可设置其To属性。
不透明度值1.0使对象完全不透明,不透明度值0.0使对象完全不可见。若要使动画的不透明度值从1.0过渡为 0.0,可以将其From属性设置为1.0,将其To属性设置为0.0。
(3)创建演⽰图板
若要向对象应⽤动画,请创建Storyboard并使⽤TargetName和TargetProperty附加属性指定要进⾏动画处理的对象和属性。
创建 Storyboard 并将动画添加为其⼦项。
并在动画中指定动画需要的三个必要属性
<Storyboard>
<DoubleAnimation From="1.0" To="0.0" Duration="0:0:1">
</DoubleAnimation>
</Storyboard>
a. From:动画属性的起始值
b. To:动画属性的结束值
c. Duration:动画执⾏所需的时间
d. TargetName:执⾏这个动画的对象名称
e. TargetProperty:执⾏这个动画的对象的属性是哪个属性
可选属性
f. AutoReverse:设置是否往返播放
g. RepeatBehavior:设置播放的次数枚举RepeatBehavior.Forever设置永久重复
在动画中指定故事版需要的两个必要属性
必须知道要在哪⾥应⽤动画。使⽤ Storyboard…::.TargetName 附加属性指定要进⾏动画处理的对象。
在下⾯的代码中,为DoubleAnimation 指定了⼀个⽬标名称 MyRectangle,这是要进⾏动画处理的对象的名称。
使⽤ TargetProperty 附加属性指定要进⾏动画处理的属性。在下⾯的代码中,动画被配置为⾯向 Rectangle 的 Opacity 属性。
<Storyboard>
<DoubleAnimation From="1.0" To="0.0" Duration="0:0:1" Storyboard.TargetName="Bd" Storyboard.TargetProperty="Opacity">
</DoubleAnimation>
</Storyboard>
(4) 将演⽰图板与触发器关联
在 XAML中应⽤和启动Storyboard的最简单的⽅法是使⽤事件触发器。
创建⼀个BeginStoryboard对象并将演⽰图板与其关联。BeginStoryboard 是⼀种应⽤和启动 Storyboard 的 TriggerAction。
<Border Name="Bd" Width="100" Height="100" Background="Cyan" Canvas.Left="200" Canvas.Top="120">
<Border.Triggers>
<EventTrigger RoutedEvent="Border.MouseDown">
canvas动画<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="1.0" To="0.0" Duration="0:0:1" Storyboard.TargetName="Bd" Storyboard.TargetProperty="Opacity"> </DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
XAML实现动画过程
1. 设置动画⽬标对象
2. 设置动画执⾏的触发器:控制动画播放的基本条件
3. 在触发器中注册路由事件:指定对象的哪个事件激活触发器
4. 激活触发器条件下开始故事版执⾏
5. 故事版中添加动画,指定动画的5个必要属性
注意
1. ⼀个故事版中可以放N多个动画
2. ⼀个故事版可以给多个对象使⽤
使⽤C#实现WPF动画
过程
1. 先创建故事版
2. 选择动画并创建动画
3. 设置动画的5个必要属性
4. 将动画添加到故事版中
5. 通过故事版的⽅法来启动动画
Storyboard sto = new Storyboard();
DoubleAnimation da = new DoubleAnimation();
da.From = 1.0;
da.To = 0.0;
//可选属性:是否往返播放
da.AutoReverse = true;
//da.RepeatBehavior = RepeatBehavior.Forever;
da.RepeatBehavior = new RepeatBehavior(2);
da.Duration = new Duration(TimeSpan.FromSeconds(3));
Storyboard.SetTarget(da, br);
Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
sto.Children.Add(da);
sto.Begin();
例如:设置矩形的若隐若现,改变颜⾊,⼤⼩,移动,旋转
xaml代码如下:
<Window x:Class="c代码实现动画.MainWindow"
xmlns="schemas.microsoft/winfx/2006/xaml/presentation"
xmlns:x="schemas.microsoft/winfx/2006/xaml"
xmlns:d="schemas.microsoft/expression/blend/2008"
xmlns:mc="/markup-compatibility/2006"
xmlns:local="clr-namespace:c代码实现动画"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="800" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded">
<Canvas Name="can">
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="80" Stroke="Black" VerticalAlignment="Top" Width="792"/>
<Button Content="消失" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Wid
th="75" Name="btnxiao" Click="Btnxiao_Click"/> <Button Content="改变颜⾊" HorizontalAlignment="Left" Margin="116,10,0,0" VerticalAlignment="Top" Width="75" Name="btncolor" Click="Btncolor_Cl ick"/>
<Button Content="改变⼤⼩" HorizontalAlignment="Left" Margin="223,10,0,0" VerticalAlignment="Top" Width="75" Name="btnsize" Click="Btnsize_Clic k"/>
<Button Content="移动" HorizontalAlignment="Left" Margin="329,10,0,0" VerticalAlignment="Top" Width="75" Name="btnyidong" Click="Btnyidong_Cli ck"/>
<Button Content="旋转" HorizontalAlignment="Left" Margin="437,10,0,0" VerticalAlignment="Top" Width="75" Name="btnxuan" Click="Btnxuan_Click"/ >
</Canvas>
</Window>
cs代码如下
namespace c代码实现动画
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
Border br = new Border();
Border br = new Border();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
br.Width = 100;
br.Height = 100;
//br.Background = Brushes.Red;
br.Background = new SolidColorBrush(Colors.Red);
Canvas.SetLeft(br,100);
Canvas.SetTop(br,100);
br.Opacity = 1.0;
can.Children.Add(br);
}
//设置若隐若现
private void Btnxiao_Click(object sender, RoutedEventArgs e)
{
if (btnxiao.Content.ToString() == "消失")
{
btnxiao.Content = "显⽰";
Storyboard st = new Storyboard();
DoubleAnimation da = new DoubleAnimation();
da.From = 1.0;
da.To = 0.0;
da.Duration = new Duration(TimeSpan.FromSeconds(3));
Storyboard.SetTarget(da,br);
Storyboard.SetTargetProperty(da,new PropertyPath("Opacity"));
st.Children.Add(da);
st.Begin();
}
else
{
btnxiao.Content = "消失";
Storyboard st = new Storyboard();
DoubleAnimation da = new DoubleAnimation();
da.From = 0.0;
da.To = 1.0;
da.Duration = new Duration(TimeSpan.FromSeconds(3));
Storyboard.SetTarget(da, br);
Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
st.Children.Add(da);
st.Begin();
}
}
//设置改变背景颜⾊
private void Btncolor_Click(object sender, RoutedEventArgs e)
{
if (btncolor.Content.ToString()=="改变颜⾊")
{
btncolor.Content = "原来颜⾊";
Storyboard st = new Storyboard();
ColorAnimation color = new ColorAnimation(Colors.Red, Colors.Green, new Duration(TimeSpan.FromSeconds(3))); Storyboard.SetTarget(color, br);
Storyboard.SetTargetProperty(color, new PropertyPath("(Border.Background).(SolidColorBrush.Color)"));
st.Children.Add(color);
st.Begin();
}
else
{
btncolor.Content = "改变颜⾊";
Storyboard st = new Storyboard();
ColorAnimation color = new ColorAnimation(Colors.Green, Colors.Red, new Duration(TimeSpan.FromSeconds(3))); Storyboard.SetTarget(color, br);
Storyboard.SetTargetProperty(color, new PropertyPath("(Border.Background).(SolidColorBrush.Color)"));
st.Children.Add(color);
st.Begin();
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论