摘要:否则动画如下时间源函数在现实生活中是需要加速以及减速后进入匀速状态,动画需要尽量的真实需要引入时间参数方程来描述加速与减速的过程。代码如下注贝塞尔曲线是用来画平滑曲线用的。。。同时我们可以用组动画在同一时刻进行时间源函数控制。
前言
应用中的动画根据需求肯定不可能是一成不变的。
当动画进行不同的状态切换的时候我们需要接下来要做什么。与见见单单的两个屏幕画面跳转不同,动画需要告诉用户什么即将到来而又要到哪里去。
键盘事件很好地解释了动画是对用户具有解释性的属性。同样视图控制器切换也可以通过大致的方向给用户提示接下来他/她要去前往哪个界面。附带细微得弹簧与碰撞效果提升整个感觉效果让APP更具有生气。
动画对你的APP而言是一个很好地介绍方式。当然需要懂动画的基本原理后,那么你才能更好掌握如何去整动画。
源头尽管高级UIKit框架中的高级API可以实现很多动画,但是还是从CALayer层入手,因为这正式animation操作的对象。
这里要知道animation加在一个视图的layer层不是直接通过改变其属性来展示动画效果的。
相反,Core Animation维护了两套layer层级:数据模型layer层树和表现layer层树。前者存放层的状态而后者展示动画值。
试想下一个视图的淡出动画。如果你在动画的任意时间点去查看层透明度值,你将得不到与屏幕所对应的透明度值。相反若你去表现层中获取将能获取到正确的透明度值。
当然你不能直接对表现层进行直接的赋值,它可以有效的用来创建新的动画或在动画期间能进行很好的互动。
通过调用-[CALayer presentationLayer] 与 -[CALayer modelLayer],可你可以在两种层级结构中轻易切换。
基本动画动画很多很多场景基本是视图的一个属性值变化从一个值到另外一个值,思考如下栗子:
上述火箭的X坐标从77变化到了455,已经超过了能展示的区间,为了能填充所有得动画帧,我们需要确定火箭在任意时间点得位置。通常用线性表达来求得火箭X坐标与时间t的关系:
使用CABasicAnimation,根据如下代码可以实现上述描述:
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; [rocket.layer addAnimation:animation forKey:@"basic"];
主要是用KVC,获取要修改的属性position.x。这是CA封好的一个使用起来比较方便得地方。。。(确实比较方便)
因为默认情况下animation不会直接修改表现层,并在动画结束的时候被移除掉。一旦动画被移除了,表现层将会回到初始的状态。
解决方案有两个:
第一种方式是直接更新数据层的属性(推荐),因为这么做使动画完全可选。
一旦动画结束并且从layer层移除,那么表现层将会与数据层契合,正好符合动画的最后一帧。
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; [rocket.layer addAnimation:animation forKey:@"basic"]; rocket.layer.position = CGPointMake(455, 61);
或者你可以通过给动画的fillMode赋值为kCAFillModeForwards同时将removedOnCompletion设置为NO来让动画保持最后一帧的状态。但是动画结束保持表现层与数据层的统一是一个良好得习惯,所以这种方法使用的时候要十分注意。
Andy Matuschak指出如果保持完成的动画将渲染一些不必要的外形带来额外的消耗。
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; animation.fillMode = kCAFillModeForward; animation.removedOnCompletion = NO; [rectangle.layer addAnimation:animation forKey:@"basic"];
非常有必要说明下每当我们创建一个动画对象,它将会为添加到layer层。这个特点我们需要记在心里因为当有多个视图的时候我们可以进行重用。如果我们第二个火箭想再第一个火箭动画完成后进行发射:
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.byValue = @378; animation.duration = 1; [rocket1.layer addAnimation:animation forKey:@"basic"]; rocket1.layer.position = CGPointMake(455, 61); animation.beginTime = CACurrentMediaTime() + 0.5; [rocket2.layer addAnimation:animation forKey:@"basic"]; rocket2.layer.position = CGPointMake(455, 111);
因为是copy的缘故,上述animation的修改只会影响到后面添加该animation的视图layer层对象。
CABasicAnimation中的byValue属性效果是当你动画结束的时候变化的属性值加上某个值(byValue)。这样的好处使得动画更容易被复用。这样我们不用特别去控制起始值和终止值。
多场景动画就是两步以上得动画。。。这时候我们可以使用泛型动画CAKeyframeAnimation。
Keyframes让我们可以随意的设定我们动画的关键位置点,并自动为我们填充关键位置点之间的动画效果。
举个输入密码,密码验证错误得动画效果:
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; animation.keyPath = @"position.x"; animation.values = @[ @0, @10, @-10, @10, @0 ]; animation.keyTimes = @[ @0, @(1 / 6.0), @(3 / 6.0), @(5 / 6.0), @1 ]; animation.duration = 0.4; animation.additive = YES; [form.layer addAnimation:animation forKey:@"shake"];
还是KVC找出动画要变动的属性,通过animation的value属性提供了中间变化点得值数组外加一个对应动画变动时间点的时间数组。(这里略了一段)
沿着指定轨迹的动画(外国佬的东西总是滔滔不绝。。无脑翻译都很累啊。。)这里先吐槽了下沿着复杂轨迹走需要保存好多好多的坐标啊。。。然后说尼玛幸好CAKeyframeAnimation提供了便捷的处理方式。
举个栗子:
CGRect boundingRect = CGRectMake(-150, -150, 300, 300); CAKeyframeAnimation *orbit = [CAKeyframeAnimation animation]; orbit.keyPath = @"position"; orbit.path = CFAutorelease(CGPathCreateWithEllipseInRect(boundingRect, NULL)); orbit.duration = 4; orbit.additive = YES; orbit.repeatCount = HUGE_VALF; orbit.calculationMode = kCAAnimationPaced; orbit.rotationMode = kCAAnimationRotateAuto; [satellite.layer addAnimation:orbit forKey:@"orbit"];
通过调用类方法我们创建了一个圆形路径用来当做动画路径。
使用calculationMode用来控制每个时间源的帧动画。设置成kCAAnimationPaced来保证匀速。
设置rotationMode来保证动画贴合轨迹进行适度旋转。否则动画如下:
时间源函数在现实生活中是需要加速以及减速后进入匀速状态,动画需要尽量的真实需要引入时间参数方程来描述加速与减速的过程。
上述已经展示过最简单得加速方式:线性加速。在CA中这个方程使用CAMediaTimingFunction类。
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @50; animation.toValue = @150; animation.duration = 1; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; [rectangle.layer addAnimation:animation forKey:@"basic"]; rectangle.layer.position = CGPointMake(150, 0);
CA还内置了一些其他时间源方程的动画效果。。此处省略N个字。。。
另外介绍下还可以根据你想要添加的控制点自定义自己的时间源方程:+functionWithControlPoints::::。
代码如下:
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.5:0:0.9:0.7]; [rocket.layer addAnimation:animation forKey:@"basic"]; rocket.layer.position = CGPointMake(150, 0);
注:贝塞尔曲线是用来画平滑曲线用的。。。
贝塞尔曲线中的几个控制点被传入+functionWithControlPoints::::(参数范围是0到1),时间源方程会根据路径调整当前的速度。
然后作者自己封了一个库来满足更复杂的动画效果包括了反弹效果:
RBBTweenAnimation *animation = [RBBTweenAnimation animation]; animation.keyPath = @"position.y"; animation.fromValue = @50; animation.toValue = @150; animation.duration = 1; animation.easing = RBBEasingFunctionEaseOutBounce;组动画
为了达到某些复杂的效果,可能需要在同一时刻改变一系列得属性值。
比如同时改变视图的位置,翻转以及Z轴得相对位置。此时使用CAAnimationGroup,我们可以这么写:
CABasicAnimation *zPosition = [CABasicAnimation animation]; zPosition.keyPath = @"zPosition"; zPosition.fromValue = @-1; zPosition.toValue = @1; zPosition.duration = 1.2; CAKeyframeAnimation *rotation = [CAKeyframeAnimation animation]; rotation.keyPath = @"transform.rotation"; rotation.values = @[ @0, @0.14, @0 ]; rotation.duration = 1.2; rotation.timingFunctions = @[ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ]; CAKeyframeAnimation *position = [CAKeyframeAnimation animation]; position.keyPath = @"position"; position.values = @[ [NSValue valueWithCGPoint:CGPointZero], [NSValue valueWithCGPoint:CGPointMake(110, -20)], [NSValue valueWithCGPoint:CGPointZero] ]; position.timingFunctions = @[ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ]; position.additive = YES; position.duration = 1.2; CAAnimationGroup *group = [[CAAnimationGroup alloc] init]; group.animations = @[ zPosition, rotation, position ]; group.duration = 1.2; group.beginTime = 0.5; [card.layer addAnimation:group forKey:@"shuffle"]; card.layer.zPosition = 1;
使用组动画的好处在于我们能见分散的动画用一个对象来控制。这样的好处在我们工厂生产出来的对象时候可以在多处复用我们的代码。同时我们可以用组动画在同一时刻进行时间源函数控制。
CA之外略。。。
大概是扯皮ios7中的运行时约束限制
以及FB的Pop开源介绍
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/15506.html
摘要:前言以前控制器容器是苹果专用呵呵,苹果一直都狠。两个子控制器视图添加到容器视图内是为了保证翻转动画不引起整个根视图的翻转。通信视图控制器需要满足可以服用并且是自包含的实体,子视图控制器也不例外。 前言 ios5以前控制器容器是苹果专用(呵呵,苹果一直都狠XD)。使用控制器容器的视图层级如下:showImg(https://segmentfault.com/img/bVdkYs); ...
摘要:前言的前言终于推出了游戏相关期刊。我们怎么设计出一款不错的游戏呢关卡长度以及交互方式。为了更好的根据实际情形进行游戏设计,我们通常把一款游戏项城市一个反馈循环。在游戏中的任一时刻,可以拥有任意数量的内嵌反馈循环。 前言的前言 OBJCIO终于推出了游戏相关期刊。我能说我想转行吗。。。不过在IT行业貌似去哪里都是要被虐。。。我还是安安静静的做个美男子吧。。 前言 扯皮游戏现状、局限...
摘要:建议尽量避免无用选项关键字。在选项关键字也是这样的原理,也只有两种情况有值跟中选项与布尔同样都用枚举定义。如果你要存一个布尔或者字符串的字典,你可以使用作为值。如果我们擅自添加了一类情况,我们需要更新所有用到该类枚举类型得代码。 前言 作者自己说自己很喜欢swift,因为他喜欢Haskell。可能看上了swift支持函数式编程的缘故。 中间扯皮各种略。。。 扯到函数编程刚开始不习...
摘要:通常,将这些状态放到一个独立的对象,并将这个对象传给视图控制器通过这样可以来观察这个状态。总结编写高度解耦简洁可维护的视图控制器 前言 总的来说试图控制器是代码最多的文件并且大多都是不可复用的代码。下面将教你做到文件瘦身、代码复用、合理代码分配。 分离数据源与协议类 一句话就是将UITableViewDataSource部分的代码单独写成一个类,通过继承它达到重用。 栗子,这里有...
阅读 1515·2021-11-15 11:38
阅读 4019·2021-09-22 15:33
阅读 1423·2021-09-07 09:59
阅读 2191·2021-08-30 09:46
阅读 2020·2019-08-30 15:43
阅读 660·2019-08-30 14:16
阅读 1944·2019-08-30 13:09
阅读 1144·2019-08-30 11:25