一步一步学习使用FireMonkey动画(1) 使用动画组件为窗体添加动态效果
FireMonkey提供了一系列的动画控件,为基于FMX(FireMonkey的简称)的应用程序开发提供了较大的灵活性。在VCL上面创建动画,需要开发人员用一个TTimer组件,然后不断的移动目标物体的位置,使得目标对象看起来像是动了一样,这需要编写大量的控制代码,而且效果并不是特别理想。
本课将介绍如下的内容:
- 使用传统TTimer创建动画。
- 使用TFloatAnimation通过改变图片的位置创建动画。
- 使用TPathAnimation创建路径动画。
本课是动画系列的入门篇,在稍后的课时中,会详细介绍这些动画组件的具体参数和使用方法。
1. 使用TTimer创建动画
下面通过一个简单的例子来演示这种做法:
1. 单击主菜单中的 File > New > Multi-Device Application - Delphi > Blank Application ,创建一个新的多设备应用程序。
建议立即单击工具栏上的Save All按钮,将单元文件保存为Form.Main.pas,将项目保存为Ani_Base.dproj。
项目结构应该像这样:

2. 在工具面板[Palette]中,添加TTimer组件,TImage组件和一个TButton组件。
选中TImage组件,在Object Inspector面板上找到MultiResBitmap属性,单击右侧的按钮打开Editing Image1.MultiResBitmap对话框,在弹出的对话框中添加一幅图片,类似下图:

请继续在Object Inspector(对象检查器或属性面板)上设置这个图片的Position.X=0;Position.Y=200。
选中按钮组件,将其Text设置为“TTimer方法”。
3. 接下来,在FormCreate事件中初始化了TTimer控件,然后为TTimer控件的OnTimer事件添加了动画的代码,并且在按钮的单击事件中启用了TTimer控件,3个事件处理代码如下:
procedure TfrmMain.Button1Click(Sender: TObject);
begin
// 切换Timer1的启用状态:当Timer1当前为启用时则禁用,当前为禁用时则启用
Timer1.Enabled := not Timer1.Enabled;
end;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
// 设置定时器间隔为100毫秒(即每0.1秒触发一次)
Timer1.Interval := 100;
// 指定定时器的触发事件处理程序为Timer1Timer
Timer1.OnTimer := Timer1Timer;
// 初始化时禁用定时器
Timer1.Enabled := False;
end;
procedure TfrmMain.Timer1Timer(Sender: TObject);
begin
{ 按菱形路径顺时针移动 }
with Image1.Position do
begin
{ 第一阶段:从左下到顶部 }
if (X < 200) and (Y <= 200) then
begin
X := X + 10; // X坐标右移10像素
Y := Y - 10; // Y坐标上移10像素
end
{ 第二阶段:从顶部到右下 }
else if (X >= 200) and (Y < 200) then
begin
X := X + 10; // X坐标右移10像素
Y := Y + 10; // Y坐标下移10像素
end
{ 第三阶段:从右下到底部 }
else if (X > 200) and (Y >= 200) then
begin
X := X - 10; // X坐标左移10像素
Y := Y + 10; // Y坐标下移10像素
end
{ 第四阶段:从底部回退到左下 }
else
begin
X := X - 10; // X坐标左移10像素
Y := Y - 10; // Y坐标上移10像素
end;
end;
end;
通过四个阶段的路径,模拟了图片的菱形动画路径,运行效果如下所示:

现在图片果然已经按菱形动画路径在跳动了。
2. 使用TFloatAnimation创建动画
3. 在工具面板[Palette]中,添加一个新的TButton组件,指定其Text属性为“使用TFloatAnimation组件”
接下来选中TImage组件,依次拉3个TFloatAnimation组件到它的下面,也就是TFloatAnimation以TImage组件作为Parent。Structure结构视图如下所示:
注意:动画组件并没有可视化图标,需要在Structure上进行查看和选择

在这里可以直接在对象检查器面板设置这3个TFloatAnimation组件的属性。由于动画组件并不会在表单上有一个特定的图标显示,需要开发人员在Structure面板上选中动画,然后在对象检查器上设置属性。在这里将使用代码方式列出参数值,以便于设置。
4. 为Button2添加如下的代码,初始化并且运行动画组件。
procedure TfrmMain.Button2Click(Sender: TObject);
begin
// 配置X轴平移动画 (FloatAnimation1)
FloatAnimation1.PropertyName := 'Position.X'; // 设置动画目标属性为X坐标
FloatAnimation1.StartFromCurrent := True; // 从当前位置开始动画
FloatAnimation1.StopValue := Image1.Position.X + 400; // 设置X轴终点值:当前位置向右400像素
FloatAnimation1.Duration := 4; // 设置动画持续时间为4秒
FloatAnimation1.Loop := True; // 设置动画循环播放
FloatAnimation1.AutoReverse := True; // 设置动画自动反向(往复运动)
// 配置Y轴向上移动动画 (FloatAnimation2) - 初始垂直移动
FloatAnimation2.PropertyName := 'Position.Y'; // 设置动画目标属性为Y坐标
FloatAnimation2.StartFromCurrent := True; // 从当前位置开始动画
FloatAnimation2.StopValue := Image1.Position.Y - 200; // 设置Y轴终点值:当前位置向上200像素
FloatAnimation2.Duration := 2; // 设置动画持续时间为2秒
// 配置Y轴往复运动动画 (FloatAnimation3) - 后续垂直振荡
FloatAnimation3.PropertyName := 'Position.Y'; // 设置动画目标属性为Y坐标
FloatAnimation3.StartFromCurrent := True; // 从当前位置开始动画
FloatAnimation3.StopValue := Image1.Position.Y + 200; // 设置Y轴终点值:当前位置向下200像素
FloatAnimation3.Duration := 4; // 设置动画持续时间为4秒
FloatAnimation3.Loop := True; // 设置动画循环播放
FloatAnimation3.AutoReverse := True; // 设置动画自动反向(往复运动)
// 检查X轴动画是否已在运行,避免重复启动
if not FloatAnimation1.Running then
begin
FloatAnimation1.Start; // 启动X轴往复平移动画
FloatAnimation2.Start; // 启动Y轴向上移动动画
// 注意:FloatAnimation3不会立即启动,将在FloatAnimation2完成后由FloatAnimation2Finish事件触发
end;
end;
procedure TfrmMain.FloatAnimation2Finish(Sender: TObject);
begin
// FloatAnimation2动画完成时的回调事件
// 当向上移动动画完成后,启动垂直方向的往复振荡动画
FloatAnimation3.Start; // 启动Y轴往复运动动画(上下振荡)
end;
当用户点击 Button2 按钮时,Image1 会开始执行一系列动画:
立即开始:在 水平方向(X轴) 上进行持续的左右往复移动(像钟摆)。
立即开始:在 垂直方向(Y轴) 上先向上移动一段距离。
随后开始:待向上的移动完成后,在 垂直方向(Y轴) 上转变为持续的上下往复移动(像弹跳)。
最终,Image1 会一边左右摇摆,一边上下弹跳,形成一个非常动态的菱形动画视觉效果。

如果与TTimer生成的动画进行比较,可以看到这里的动画要顺滑很多。
3. 使用TPathAnimation创建动画
5. 选中Image1控件,然后从工具栏拖一个TPathAnimation控件到其上面,使之成为Image1的子组件。

然后添加一个按钮,其Text属性设置为“使用TPathAnimation组件”,为其添加如下的事件处理代码:
// 主窗体中 Button3 的点击事件处理过程
procedure TfrmMain.Button3Click(Sender: TObject);
begin
// 设置路径动画的路径
// 首先将路径的起始点移动到坐标原点 (0, 0)
PathAnimation1.Path.MoveTo(PointF(0, 0));
// 从当前点绘制直线到坐标 (200, -200)
PathAnimation1.Path.LineTo(PointF(200, -200));
// 从当前点继续绘制直线到坐标 (400, 0)
PathAnimation1.Path.LineTo(PointF(400, 0));
// 从当前点继续绘制直线到坐标 (200, 200)
PathAnimation1.Path.LineTo(PointF(200, 200));
// 闭合路径:从当前点绘制直线回起始点,形成封闭图形
PathAnimation1.Path.ClosePath;
// 设置动画循环播放属性为 True,动画将无限循环
PathAnimation1.Loop := True;
// 设置动画完成一次完整路径所需的时间为 8 秒
PathAnimation1.Duration := 8;
// 启动路径动画
PathAnimation1.Start;
end;
上面的代码首先构建了一条封闭的路径,然后TImage会沿着这条路径来移动位置,形成动画效果。

可以看到,它实现了类似前是面2种的动画效果。
总结
传统的TTimer模式的动画,需要程序员控制动画的具体位置,对于复杂的动画,往往需要编写大量的代码。由于所有逻辑和UI更新都在OnTimer事件中完成,如果计算复杂会直接阻塞UI。
FireMonkey(以后简称FMX)提供的动画组件具有如下的优势:
- 可以在设计时进行动画的配置,动画间隔由FireMonkey的渲染管线和计时器统一管理,通常利用GPU进行平滑渲染。
- 动画的进度由内部高精度时钟控制,与持续时间(Duration)严格绑定,帧率是自适应的。
- 动画引擎在后台处理所有计算,并通过安全的方式更新UI,开发者无需关心线程问题。
- 内置插值(Inverse, Circular, Elastic等)、自动反转、循环、路径跟随等高级功能。
FMX除了提供丰富的动画组件外,还在TFmxObject对象中整合了动画函数,使得FireMonkey可以创造出非常丰富的动画效果的软件。
接下来会通过几节内容详细介绍这些动画组件的具体使用方法。
一步一步学习使用FireMonkey动画(1) 使用动画组件为窗体添加动态效果的更多相关文章
- 12.Linux软件安装 (一步一步学习大数据系列之 Linux)
1.如何上传安装包到服务器 有三种方式: 1.1使用图形化工具,如: filezilla 如何使用FileZilla上传和下载文件 1.2使用 sftp 工具: 在 windows下使用CRT 软件 ...
- (转) 一步一步学习ASP.NET 5 (四)- ASP.NET MVC 6四大特性
转发:微软MVP 卢建晖 的文章,希望对大家有帮助.原文:http://blog.csdn.net/kinfey/article/details/44459625 编者语 : 昨晚写好的文章居然csd ...
- (转) 一步一步学习ASP.NET 5 (二)- 通过命令行和sublime创建项目
转发:微软MVP 卢建晖 的文章,希望对大家有帮助. 注:昨天转发之后很多朋友指出了vNext的命名问题,原文作者已经做出了修改,后面的标题都适用 asp.net 5这个名称. 编者语 : 昨天发了第 ...
- 一步一步学习SignalR进行实时通信_1_简单介绍
一步一步学习SignalR进行实时通信\_1_简单介绍 SignalR 一步一步学习SignalR进行实时通信_1_简单介绍 前言 SignalR介绍 支持的平台 相关说明 OWIN 结束语 参考文献 ...
- 一步一步学习SignalR进行实时通信_8_案例2
原文:一步一步学习SignalR进行实时通信_8_案例2 一步一步学习SignalR进行实时通信\_8_案例2 SignalR 一步一步学习SignalR进行实时通信_8_案例2 前言 配置Hub 建 ...
- 一步一步学习SignalR进行实时通信_9_托管在非Web应用程序
原文:一步一步学习SignalR进行实时通信_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信\_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信_9_托管在非We ...
- 一步一步学习SignalR进行实时通信_7_非代理
原文:一步一步学习SignalR进行实时通信_7_非代理 一步一步学习SignalR进行实时通信\_7_非代理 SignalR 一步一步学习SignalR进行实时通信_7_非代理 前言 代理与非代理 ...
- 一步一步学习SignalR进行实时通信_5_Hub
原文:一步一步学习SignalR进行实时通信_5_Hub 一步一步学习SignalR进行实时通信\_5_Hub SignalR 一步一步学习SignalR进行实时通信_5_Hub 前言 Hub命名规则 ...
- 一步一步学习SignalR进行实时通信_6_案例
原文:一步一步学习SignalR进行实时通信_6_案例 一步一步学习SignalR进行实时通信\_6_案例1 一步一步学习SignalR进行实时通信_6_案例1 前言 类的定义 各块功能 后台 上线 ...
- 一步一步学习SignalR进行实时通信_4_Hub
原文:一步一步学习SignalR进行实时通信_4_Hub 一步一步学习SignalR进行实时通信\_4_Hub SignalR 一步一步学习SignalR进行实时通信_4_Hub 前言 创建Hub 配 ...
随机推荐
- 腾讯云对象存储工具类和demo
使用 package com.ruoyi; import java.io.File; public class mytest { private static String secretId = &q ...
- 【深度评测】Joomla Auto Readmore插件:自动提取缩略图+智能摘要,双引擎驱动内容效率革命
"文章缩略图与摘要分离管理.重复上传图片.移动端封面图比例失调--"这些Joomla站长的经典痛点,如今被Auto Readmore插件的全自动缩略图提取功能彻底终结.本文将深度解 ...
- Vue 学习笔记 [Part 3]
作者:故事我忘了¢个人微信公众号:程序猿的月光宝盒 目录 〇.高阶函数 0.1 filter() 0.2 map() 0.3 reduce() 一. 表单绑定v-model 1.1. v-model的 ...
- python之PypI打包whl文件
一.简单介绍 python中我们经常会用到第三方的包作为工具,比如爬虫解析工具,网络请求工具等.之所以要把它封装成包,意识为了技术与业务分离,二是为了能多 项目多平台共用.python里面用到的第三方 ...
- PHP中的多线程与异步编程常见误区
本文由 ChatMoney团队出品 在PHP开发中,多线程和异步编程是提高应用性能和响应速度的重要手段.然而,这些技术也带来了许多挑战和陷阱,如共享状态冲突.死锁.超时.资源泄漏以及调试困难等.本文将 ...
- windows制作macos的U盘启动
苹果电脑型号对应系统版本号对照表 这里参考. 系统下载 macos的系统 对比windows系统,真的是资源太少了. 有一个工具叫做 GibMacOS,一键下载Macos系统工具,我没试用过. 启动盘 ...
- macBook本地安装mysql
下载软件https://dev.mysql.com/downloads/ 找到MySQL Community Server,点击下载下载页选择合适的版本下载就行,一般选择第一个macOS 10.15 ...
- C++ basic_string::_M_construct null not valid
这个错误我在构造函数中爆出了错误 累坏我了 一般来说是赋值了不该赋的值 string 类型的初始化 用 int 结果炸了
- P9713 「QFOI R1」抱抱 题解
P9713 「QFOI R1」抱抱 题解 Sol 前置知识:长方体体积公式:\(V = abh\). 我们知道,切割掉 \(x \le k\) 的部分就是把 \(a\) 减去 \(k\),切割掉 \( ...
- SciTech-AV-Audio-Coding-Sampling-PCM:Multiplex(FD频分/TD时分多工)+DPCM(Delta增量)+ADPCM(Adaptive Delta自适应增量) + Oversampling超采样
pdf: https://web.stanford.edu/class/ee179/lectures/notes13.pdf EE 179: Communication Systems Textboo ...