<转> core Animation动画-2

本文深入探讨了CAKeyFrameAnimation在iOS开发中的高级应用,通过具体实例展示了如何利用关键帧动画实现复杂的运动路径,包括绕矩形循环跑动的功能演示,并详细解析了CAKeyFrameAnimation的关键属性及其使用方法。
在上一篇专题中我们提到,CAAnimation可分为以下四种:

1
2
3
4
5
6
7
8
1.CABasicAnimation
通过设定起始点,终点,时间,动画会沿着你这设定点进行移动。可以看做特殊的CAKeyFrameAnimation
2.CAKeyframeAnimation
Keyframe顾名思义就是关键点的frame,你可以通过设定CALayer的始点、中间关键点、终点的frame,时间,动画会沿你设定的轨迹进行移动
3.CAAnimationGroup
Group也就是组合的意思,就是把对这个Layer的所有动画都组合起来。PS:一个layer设定了很多动画,他们都会同时执行,如何按顺序执行我到时候再讲。
4.CATransition
这个就是苹果帮开发者封装好的一些动画,
CABasicAnimation算是CAKeyFrameAnimation的特殊情况,即不考虑中间变换过程,只考虑起始点与目标点就可以了。而CAKeyFrameAnimation则更复杂一些,允许我们在起点与终点间自定义更多内容来达到我们的实际应用需求!比如,手机淘宝中,当你添加物品到购物车后会出现将物品抛到购物车的效果,这种效果实现起来也不难,无非是先绘制抛物线在执行position以及scale的GroupAnimation而已,以下图1是我模仿该功能小玩出来的一个demo示例,感兴趣的话你可以自己实现一下试试:D.

                    

                        图1                                              图2 

下面我们以实现“小圆球绕矩形跑道循环跑动”为目标开始对CAKeyFrameAnimation的介绍,如图2所示。小圆球的运动轨迹可分为四段,每段的运动速度不同,第一段中先慢后快再慢。先贴上源码方便后面分析:

 

复制代码
 1 //绕矩形循环跑
 2 - (void)initRectLayer
 3 {
 4     rectLayer = [[CALayer alloc] init];
 5     rectLayer.frame = CGRectMake(15, 200, 30, 30);
 6     rectLayer.cornerRadius = 15;
 7     rectLayer.backgroundColor = [[UIColor blackColor] CGColor];
 8     [self.view.layer addSublayer:rectLayer];
 9     CAKeyframeAnimation *rectRunAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
10     //设定关键帧位置,必须含起始与终止位置
11     rectRunAnimation.values = @[[NSValue valueWithCGPoint:rectLayer.frame.origin],
12                                 [NSValue valueWithCGPoint:CGPointMake(320 - 15,
13                                                                       rectLayer.frame.origin.y)],
14                                 [NSValue valueWithCGPoint:CGPointMake(320 - 15,
15                                                                       rectLayer.frame.origin.y + 100)],
16                                 [NSValue valueWithCGPoint:CGPointMake(15, rectLayer.frame.origin.y + 100)],
17                                 [NSValue valueWithCGPoint:rectLayer.frame.origin]];
18     //设定每个关键帧的时长,如果没有显式地设置,则默认每个帧的时间=总duration/(values.count - 1)
19     rectRunAnimation.keyTimes = @[[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.6],
20                                   [NSNumber numberWithFloat:0.7], [NSNumber numberWithFloat:0.8],
21                                   [NSNumber numberWithFloat:1]];
22     rectRunAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
23                                          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
24                                          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
25                                          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
26     rectRunAnimation.repeatCount = 1000;
27     rectRunAnimation.autoreverses = NO;
28     rectRunAnimation.calculationMode = kCAAnimationLinear;
29     rectRunAnimation.duration = 4;
30     [rectLayer addAnimation:rectRunAnimation forKey:@"rectRunAnimation"];
31 }
复制代码
 

                    

 

                                      图3

对CAKeyFrameAnimation的使用与CABasicAnimation大同小异,有些属性是共通的,因此小翁建议你先阅读上一篇文章。KeyFrame的意思是关键帧,所谓“关键”就是改变物体运动趋势的帧,在该点处物体将发生运动状态,比如矩形的四个角,抛物线的顶点等。因此,聪明的你应该知道了,在上述例子中共有5个关键帧(图3中的ABCDE)。上个关键帧到当前关键帧之间的路径与当前关键帧相联系,比如AB->B,我们可以对AB进行定义动画定义,而自定义要通过众多CAKeyFrameAnimation的属性达到目的。CAKeyFrameAnimation的使用中有以下主要的属性需要注意,有些属性可能比较绕比较难以理解,我会结合图片进行必要的说明。

(1)values属性

values属性指明整个动画过程中的关键帧点,例如上例中的A-E就是通过values指定的。需要注意的是,起点必须作为values的第一个值。

(2)path属性

作用与values属性一样,同样是用于指定整个动画所经过的路径的。需要注意的是,values与path是互斥的,当values与path同时指定时,path会覆盖values,即values属性将被忽略。例如上述例子等价于代码中values方式的path设置方式为:

复制代码
1     CGMutablePathRef path = CGPathCreateMutable();
2     CGPathMoveToPoint(path, NULL, rectLayer.position.x - 15, rectLayer.position.y - 15);
3     CGPathAddLineToPoint(path, NULL, 320 - 15, rectLayer.frame.origin.y);
4     CGPathAddLineToPoint(path, NULL, 320 - 15, rectLayer.frame.origin.y + 100);
5     CGPathAddLineToPoint(path, NULL, 15, rectLayer.frame.origin.y + 100);
6     CGPathAddLineToPoint(path, NULL, 15, rectLayer.frame.origin.y);
7     rectRunAnimation.path = path;
8     CGPathRelease(path);
复制代码
(3)keyTimes属性

该属性是一个数组,用以指定每个子路径(AB,BC,CD)的时间。如果你没有显式地对keyTimes进行设置,则系统会默认每条子路径的时间为:ti=duration/(5-1),即每条子路径的duration相等,都为duration的1\4。当然,我们也可以传个数组让物体快慢结合。例如,你可以传入{0.0, 0.1,0.6,0.7,1.0},其中首尾必须分别是0和1,因此tAB=0.1-0, tCB=0.6-0.1, tDC=0.7-0.6, tED=1-0.7.....

(4)timeFunctions属性

用过UIKit层动画的同学应该对这个属性不陌生,这个属性用以指定时间函数,类似于运动的加速度,有以下几种类型。上例子的AB段就是用了淡入淡出效果。记住,这是一个数组,你有几个子路径就应该传入几个元素

1 kCAMediaTimingFunctionLinear//线性
2 kCAMediaTimingFunctionEaseIn//淡入
3 kCAMediaTimingFunctionEaseOut//淡出
4 kCAMediaTimingFunctionEaseInEaseOut//淡入淡出
5 kCAMediaTimingFunctionDefault//默认
(5)calculationMode属性

该属性决定了物体在每个子路径下是跳着走还是匀速走,跟timeFunctions属性有点类似

1 const kCAAnimationLinear//线性,默认
2 const kCAAnimationDiscrete//离散,无中间过程,但keyTimes设置的时间依旧生效,物体跳跃地出现在各个关键帧上
3 const kCAAnimationPaced//平均,keyTimes跟timeFunctions失效
4 const kCAAnimationCubic//平均,同上
5 const kCAAnimationCubicPaced//平均,同上
此外,动画的暂停与开始可以通过下面的方式做到:

复制代码
 1 -(void)pauseLayer:(CALayer*)layer
 2 {
 3     CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
 4     layer.speed = 0.0;
 5     layer.timeOffset = pausedTime;
 6 }
 7 
 8 -(void)resumeLayer:(CALayer*)layer
 9 {
10     CFTimeInterval pausedTime = [layer timeOffset];
11     layer.speed = 1.0;
12     layer.timeOffset = 0.0;
13     layer.beginTime = 0.0;
14     CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
15     layer.beginTime = timeSincePause;
16 }
复制代码
更多更详细的关于这些属性的介绍可以进一步阅读此文。

关于CAKeyFrameAnimation的介绍基本结束了,在文章的最后,开源一个小翁封装的抛物动画代码,上文的图1就是在这份代码的基础上实现的:

 ThrowLineTool.h
 ThrowLineTool.m
 使用方法
 

  

转载于:https://www.cnblogs.com/deng37s/p/4599945.html

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>优化版文字淡入效果</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif; line-height: 1.6; color: #333; padding: 20px; max-width: 1200px; margin: 0 auto; } .fade-container { background-color: #aabcda; border-radius: 8px; padding: 40px; margin: 40px auto; overflow: hidden; } /* 使用cubic-bezier实现更顺滑的动画曲线 */ @keyframes fadeIn { 0% { opacity: 0; transform: translateY(15px); } 100% { opacity: 1; transform: translateY(0); } } .fade-title { font-weight: bold; font-size: 2em; margin-bottom: 25px; color: #1a3a5f; animation: fadeIn 1.2s cubic-bezier(0.22, 0.61, 0.36, 1) forwards; } .fade-content { font-size: 1.5em; font-weight: normal; color: #2c3e50; animation: fadeIn 1.5s cubic-bezier(0.22, 0.61, 0.36, 1) forwards; animation-delay: 0.3s; line-height: 1.7; } .content-section { margin: 30px 0; padding: 20px; background: #f8f9fc; border-radius: 8px; } h2 { margin-bottom: 15px; color: #1a3a5f; } p { margin-bottom: 15px; } </style> </head> <body> <div class="fade-container"> <h1 class="fade-title">优化后的平滑淡入效果</h1> <p class="fade-content"> 此文本采用了更顺滑的CSS3淡入动画效果。通过使用cubic-bezier缓动函数,动画表现更加流畅自然, 减少了机械感,同时保持了响应式特性。容器阴影已按需移除,保留了指定的#aabcda背景色。 </p> </div> <div class="content-section"> <h2>技术优化点</h2> <p> 1. 使用自定义cubic-bezier曲线替代标准ease-out,动画更加平滑流畅[^1] </p> <p> 2. 动画元素初始上移量从20px减少到15px,视觉上更舒适自然 </p> <p> 3. 文本采用渐变深蓝色系,提高在淡蓝色背景上的可读性 </p> <p> 4. 移除所有容器阴影效果,保持页面简洁性 </p> <p> 5. 优化了文本行间距和段落间距,提升整体阅读体验[^2] </p> </div> <div class="content-section"> <h2>布局稳定性</h2> <p> 此实现完全遵守不影响网页布局的设定要求。所有外边距(margin)和内边距(padding)都经过精确计算, 避免任何不必要的布局偏移[^3]。不同设备上均能保持一致的视觉表现。 </p> </div> <div class="content-section"> <h2>CSS代码说明</h2> <p> 淡入动画关键帧: <pre> @keyframes fadeIn { 0% { opacity: 0; transform: translateY(15px); } 100% { opacity: 1; transform: translateY(0); } }</pre> </p> <p> 应用示例: <pre> .fade-title { animation: fadeIn 1.2s cubic-bezier(0.22, 0.61, 0.36, 1) forwards; }</pre> </p> </div> <script> // 确保动画在页面加载时正常触发 document.addEventListener('DOMContentLoaded', function() { const elements = document.querySelectorAll('.fade-title, .fade-content'); elements.forEach(el => { // 重置动画确保在浏览器加载完成后触发 el.style.animation = 'none'; setTimeout(() => { el.style.animation = ''; }, 10); }); }); </script> </body> </html> 请在这个代码的基础上删除容器圆角,淡入前隐藏文本,不要闪一下
06-13
<error> <unique>0x00000000005760B0</unique> <tid>1</tid> <kind>Leak_DefinitelyLost</kind> <xwhat> <text>32 bytes in 1 blocks are lost in loss record 1167725 of 1387445 (#5726384)</text> <leakedbytes>32</leakedbytes> <leakedblocks>1</leakedblocks> </xwhat> <stack> <frame> <fn>malloc</fn> </frame> <frame> <ip>0x00007FFA1663F24B</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\libstdc++-6.dll</obj> <fn>_Znwy</fn> </frame> <frame> <ip>0x000000006891BFF4</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\Qt5Core.dll</obj> <fn>_ZN12QEasingCurveC1ENS_4TypeE</fn> </frame> <frame> <ip>0x000000006888B336</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\Qt5Core.dll</obj> <fn>_ZN17QVariantAnimation12valueChangedERK8QVariant</fn> </frame> <frame> <ip>0x000000006888FF53</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\Qt5Core.dll</obj> <fn>_ZN18QPropertyAnimationC1EP7QObjectRK10QByteArrayS1_</fn> </frame> <frame> <ip>0x000000000ACF8558</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuWidgets.dll</obj> <fn>_ZN14TjuWidgetTitle11setFloatingEb</fn> </frame> <frame> <ip>0x000000000AD44218</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuWidgets.dll</obj> <fn>_ZN14TjuWidgetTitle11setFloatingEb</fn> </frame> <frame> <ip>0x000000000AE7B470</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuWidgets.dll</obj> <fn>_ZN11TjuECEngine21TjuS57MilitaryManagerC1EP7QWidget</fn> </frame> <frame> <ip>0x000000000042EE9B</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuMain.exe</obj> </frame> <frame> <ip>0x00000000004165CE</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuMain.exe</obj> </frame> <frame> <ip>0x00000000008BF0DF</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuMain.exe</obj> </frame> <frame> <ip>0x00000000004013C6</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuMain.exe</obj> </frame> <frame> <ip>0x00000000004014CA</ip> <obj>E:\q5142\qt5pro\TjuECS_QT5\bin\win\TjuMain.exe</obj> </frame> </stack> </error>
07-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值