WPF界面设计技巧(7)—模拟电梯升降的缓动动画

如同Flash一样,WPF的亮点之一也在于其擅于表现平滑的动画效果,但以移动动画来说,仅凭简单的起始位置、目标位置,所产生的动画仍会非常生硬,这种动画忽略了移动开始时的加速过程与移动结束时的减速过程。
WPF在关键帧动画中提供了样条内插(Spline)型的关键帧,用以控制变化的速率曲线,但这东西实在有些复杂,且不够形象化,我研究很久也没明白如何实现“缓入——缓出”的效果,随后我从一本经典牛X却鲜有人知的过时的FlashMX教程中提取了一个缓动函数,我们将用这个函数来较真实地模拟电梯的升降行为。
至于那本牛X的书,我以后会为大家介绍,我个人认为,那本书应当作为平面动画编程的必修经典,而它却被粗烂地印刷,并一直摆在书店里不引人注目的位置。
进入正题:
首先在界面设计器中添加一个 Rectangle ,用以代表直升电梯,然后添加4个 RadioButton 代表几个楼层的呼叫按钮。
稍加美化,即为下图所示:

RadioButton 的样式直接用来当电梯按钮,略显生硬,我们用下面的代码来美化一下它:
Code
<Style TargetType="RadioButton">
<Setter Property="Foreground" Value="#ADB7BD"/>
<Setter Property="FontSize" Value="32"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<ContentPresenter/>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="#BD5E00" Duration="0:0:0.3" BeginTime="0:0:0.1" Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.2" BeginTime="0:0:0.2" Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
现在就比较帅了:

接下来为所有 RadioButton 添加统一的事件处理函数:

至此界面部分的全部代码如下,需要注意的是,所有元素都需要手动调整一下它们在Grid中的对齐方位,将其设为 Left 和 Top。要知道,设计器会在你拖动它们的时候为其胡乱改变对其方位,这会使你的元素没有统一的定位标准,导致几乎没法用代码统一操控它们的位置。
Code
<Window x:Class="缓动动画.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="398" Width="381" x:Name="window" Background="{StaticResource back}" Loaded="window_Loaded">
<Window.Resources>
<Style TargetType="RadioButton">
<Setter Property="Foreground" Value="#ADB7BD"/>
<Setter Property="FontSize" Value="32"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<ContentPresenter/>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="#BD5E00" Duration="0:0:0.3" BeginTime="0:0:0.1" Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.2" BeginTime="0:0:0.2" Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Rectangle Fill="{StaticResource box}" Margin="45,265,0,0" Name="rectangle1" HorizontalAlignment="Left" Width="50" Height="50" VerticalAlignment="Top" />
<RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,205,0,0" VerticalAlignment="Top">1F</RadioButton>
<RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,125,0,0" VerticalAlignment="Top">2F</RadioButton>
<RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,45,0,0" VerticalAlignment="Top">3F</RadioButton>
<RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,285,0,0" VerticalAlignment="Top" IsChecked="True">B1</RadioButton>
</Grid>
</Window>
在后台书写事件处理函数代码:

请不要惊讶我使用中文命名函数,假如你看过我自己写的程序的源代码,你就会对此保持沉默。
这就是传说中的中文函数“开始升降”:

在这个函数中,我们创建了一个 Thickness 的关键帧动画,Thickness 通常用来代表一个元素的上下左右4边,比如 Border 四个边的粗细就是用 Thickness 描述的,而这里的 Margin 属性也是 Thickness 类型。
一些要点我写在了图里,这里就不累述了。
“缓动计算”,是的,又一个神奇的中文函数,你可以在下面完整的源码中看看它是如何运算的,至少我是对它的内容毫无兴趣。
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Animation; namespace 缓动动画
{
/**//// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
} private void window_Loaded(object sender, RoutedEventArgs e)
{ } Storyboard s = new Storyboard(); public double 缓动计算(TimeSpan 总时间, TimeSpan 现在时间, double 初始值, double 变动量)
{
var t = 现在时间.TotalSeconds /( 总时间.TotalSeconds / 2);
if (t < 1) return (变动量 / 2 * Math.Pow(t, 5) + 初始值);
return (变动量 / 2 * (Math.Pow(t - 2, 5) + 2) + 初始值);
} private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
开始升降((sender as RadioButton).Margin.Top - 5);
} public void 开始升降(double 目标高度)
{
ThicknessAnimationUsingKeyFrames d = new ThicknessAnimationUsingKeyFrames();
d.Duration = new Duration(TimeSpan.FromSeconds(Math.Abs((目标高度-rectangle1.Margin.Top)/80)));
for (int i = 0; i < 100; i++)
{
var t = new Thickness();
t.Left = rectangle1.Margin.Left;
t.Right = rectangle1.Margin.Right;
t.Bottom = rectangle1.Margin.Bottom;
t.Top=缓动计算(d.Duration.TimeSpan, TimeSpan.FromSeconds(d.Duration.TimeSpan.TotalSeconds / 100 * i), rectangle1.Margin.Top, 目标高度-rectangle1.Margin.Top);
d.KeyFrames.Add(new LinearThicknessKeyFrame(t, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(d.Duration.TimeSpan.TotalSeconds / 100 * i))));
}
s.Children.Add(d);
Storyboard.SetTargetName(d, rectangle1.Name);
Storyboard.SetTargetProperty(d, new PropertyPath(Rectangle.MarginProperty));
s.Begin(rectangle1);
}
}
}
现在编译运行吧,随便点击一个楼层,你将会看到电梯平缓的起步,然后平缓的停靠在你所选的楼层上。

当然,即使是这样具有缓动效果的电梯,乘客也是很难生还的,但至少会比生硬的上飞下坠要好很多啦。
WPF界面设计技巧(7)—模拟电梯升降的缓动动画的更多相关文章
- WPF界面设计技巧(8)—自制山寨版CheckListBox
原文:WPF界面设计技巧(8)-自制山寨版CheckListBox 近年来IT市场山寨横行啊,我们今天也来发扬一下山寨精神,搞个自制的CheckListBox出来. 喏,CheckListBox 就是 ...
- WPF界面设计技巧(3)—实现不规则动画按钮
原文:WPF界面设计技巧(3)-实现不规则动画按钮 发布了定义WPF按钮的教程后,有朋友问能否实现不规则形状的按钮,今天我们就来讲一下不规则按钮的制作. 不规则按钮的做法实际上和先前我们做不规则窗体的 ...
- WPF界面设计技巧(11)-认知流文档 & 小议WPF的野心
原文:WPF界面设计技巧(11)-认知流文档 & 小议WPF的野心 流文档是WPF中的一种独特的文档承载格式,它的书写和呈现方式都很像HTML,它也几乎具备了HTML的绝大多数优势,并提供了更 ...
- WPF界面设计技巧(10)-样式的继承
原文:WPF界面设计技巧(10)-样式的继承 PS:现在我的MailMail完工了,进入内测阶段了,终于可以腾出手来写写教程了哈,关于MailMail的介绍及内测程序索取:http://www.cnb ...
- WPF界面设计技巧(9)—使用UI自动化布局
原文:WPF界面设计技巧(9)-使用UI自动化布局 最近一直没时间更新这系列文章,因为我一直在埋头编写我的第一个WPF应用程序:MailMail 今天开始编写附属的加密/解密工具,对UI自动化布局有些 ...
- WPF界面设计技巧(6)—玩玩数字墨水手绘涂鸦
原文:WPF界面设计技巧(6)-玩玩数字墨水手绘涂鸦 想让你的程序支持鼠标及手写笔涂鸦吗?只要敲入“<InkCanvas/>”这几个字符,你就会领悟什么叫“很好很强大”,今天我们来做一个手 ...
- WPF界面设计技巧(5)—自定义列表项呈现内容
原文:WPF界面设计技巧(5)-自定义列表项呈现内容 接续上次的程序,稍微改动一下原有样式,并添加一个数据模板,我们就可以达成下面这样的显示功能: 鼠标悬停于文件列表项上,会在工具提示中显示图像缩略图 ...
- WPF界面设计技巧(4)—自定义列表项样式
原文:WPF界面设计技巧(4)-自定义列表项样式 有前面修改按钮样式的基础,我们可以尝试来定制一个即好看又好用的 ListBox ,今天先来讲“好看”部分. 打开 Microsoft Visual S ...
- WPF界面设计技巧(2)—自定义漂亮的按钮样式
原文:WPF界面设计技巧(2)-自定义漂亮的按钮样式 上次做了个很酷的不规则窗体,这次我们来弄点好看的按钮出来,此次将采用纯代码来设计按钮样式,不需要 Microsoft Expression Des ...
随机推荐
- 采用管道处理HTTP请求
采用管道处理HTTP请求 之所以称ASP.NET Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求.ASP. NET ...
- 【玩转cocos2d-x之四十】怎样在Cocos2d-x 3.0中使用opengl shader?
有小伙伴提出了这个问题.事实上GLProgramCocos2d-x引擎自带了.全然能够直接拿来用. 先上图吧. 使用opengl前后的对照: watermark/2/text/aHR0cDovL2Js ...
- Lucene.Net 2.3.1开发介绍 —— 三、索引(三)
原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(三) 3.Field配置所产生的效果 索引数据,简单的代码,只要两个方法就搞定了,而在索引过程中用到的一些类里最简单,作用也不小的就是F ...
- POJ 2632 Crashing Robots(较为繁琐的模拟)
题目链接:http://poj.org/problem?id=2632 题目大意:题意简单,N个机器人在一个A*B的网格上运动,告诉你机器人的起始位置和对它的具体操作,输出结果: 1.Robot i ...
- 自己定义UITabBarController
网上大多的自己定义TabBar都是继承View的,项目中要用到path+Tabbat这种话(path用的MMDrawerController这个框架),继承View的Tabbar是无法满足条件的(不是 ...
- PHP中抽象类与接口的应用场景
<?php /*** ====笔记部分==== 接口的具体语法: 0:以人类为, class Human 是人的草图 而接口 是零件 可以用多种零件组合出一种新特种来. 1: 如上,接口本身即是 ...
- 绘制FastMM内存分配流程图(小块内存分配)
http://blog.csdn.net/henreash/article/details/38751353
- Delphi的组件读写机制
Delphi的组件读写机制(一) 一.流式对象(Stream)和读写对象(Filer)的介绍在面向对象程序设计中,对象式数据管理占有很重要的地位.在Delphi中,对对象式数据管理的支持方式是其一大特 ...
- setenv 和 set
setenv 和 set 是在csh系列的命令,当然bash中也有set,还是有出入的. set 是对当前进程有效,不会传递给子进程 setenv 不仅对当前进程有效,也会传递给子进程. 语法 ...
- 一个用 C 语言写的迷你版 2048 游戏,仅仅有 500个字符
Jay Chan 用 C 语言写的一个迷你版 2048 游戏,仅仅有 487 个字符. 来围观吧 M[16],X=16,W,k;main(){T(system("stty cbreak&qu ...