21- 《A GUIDE TO IOS ANIMATION 2.0》(杨骑滔)三章.CoreAnimation-学习笔记: 源码分析和盲点记录
第一个案例: Twitter 的启动动画
这个案例之前有看过.当时觉得很有意思. 今天看了杨骑滔给出的实现思路之后,才发现实现代码不难,难的还是你的实现的思路. 我们仔细观察,书中的启动动画,开始的页面是从程序启动之后一直到进入根控制器都是同一个,而且明显,要比我们平时的启动界面停留的时间要长.这个的实现思路和我们看到的很多主流APP进入之后,会有一个广告界面,还有倒计时.这个肯定是系统自带的LaunchScreen.xib
启动完成之后,在显示根控制器之前穿插的. 只不过,广告和启动是不同的页面,我们这里是需要两个样式一模一样的页面.
原理,我就不赘述了.我想看了书的人和看了源码的人早已经了然于胸. 现在只是记录下自己的知识的盲点.
UIWindow的两个方法
[self.window makeKeyAndVisible];
和 self.window.rootViewController
的具体作用:
-------- 占位行 ------------
mask属性
“在开始之前,我们先了解一下 Layer 的 mask 属性。
@property(strong) CALayer *mask;
可以发现 mask 也是一个 CALayer”
--- 摘录来自: 杨骑滔(KittenYang). “A GUIDE TO IOS ANIMATION”。 iBooks.
//logo mask 添加一个遮罩,图片透明和不透明的地方反转
CALayer *maskLayer = [CALayer layer];
maskLayer.contents = (id)[UIImage imageNamed:@"1"].CGImage; //必须是CGImageRef
maskLayer.position = navc.view.center;
maskLayer.bounds = CGRectMake(0, 0, 60, 60);
navc.view.layer.mask = maskLayer; //为mask(CALayer)属性赋值之后,露出window是黑色的,必须通过改变self.window.background的颜色
CoreAnimation - CAKeyframeAnimation
---- 以下均为原文,摘录来自: 杨骑滔(KittenYang). “A GUIDE TO IOS ANIMATION”。 iBooks.
- 顾名思义,CAKeyframeAnimation 就相当于 Flash 里的关键帧动画”
- CAKeyframeAnimation 中我们通过 keyPath 就可以指定动画的类型。”
- 然后,我们把每个关键帧的对应参数赋值给 CAKeyframeAnimation 的 values 属性。代码中,我设置了3个关键帧,transformAnimation.values = xxx
- 设置对应的时间点 transformAnimation.keyTimes = xxx
- 但是我们还要注意。当你给一个 CALayer 添加动画的时候,动画其实并没有改变这个 layer 的实际属性。取而代之的,系统会创建一个原始 layer 的拷贝。在文档中,苹果称这个原始 layer 为 Model Layer ,而这个复制的 layer 则被称为 Presentation Layer 。 Presentation Layer 的属性会随着动画的进度实时改变,而 Model Layer 中对应的属性则并不会改变。所以如果你想要获取动画中每个时刻的状态,请使用 layer 的 func presentationLayer() -> AnyObject!
- 为了让动画在结束之后不突然回到了初始状态, 引出 removedOnCompletion 和 fillMode 了。
removedOnCompletion 的官方解释是:
/* When true, the animation is removed from the render tree once its- active duration has passed. Defaults to YES. */
也就是默认情况下系统会在 duration 时间后自动移除这个 CAKeyframeAnimation。当 remove 了某个动画,那么系统就会自动销毁这个 layer 的 Presentation Layer ,只留下 Model Layer ”
- 你需要先把 removedOnCompletion 设置为 false ,然后设置 fillMode 为kCAFillModeForwards” (TIPS: 对于 CAAnimation ,你需要将其 removedOnCompletion 设置为 false 才行,要不然 fillMode 将不起作用。”)。但设置 removedOnCompletion 和 fillMode 不是正确的方式(这个之后再详细说明)。
- 所以一个好动画离不开一堆好参数。
第二个案例: 圆圈遮罩的转场动画
这个案例讲的是转场动画,这个Demo的效果可以看格瓦拉
选中一个条目之后,
关于转场动画
“iOS7 开始苹果推出了自定义转场的 API 。从此,任何可以用 CoreAnimation 实现的动画,都可以出现在两个 ViewController 的切换之间。”
“苹果在 UINavigationControllerDelegate
和 UIViewControllerTransitioningDelegate
中给出了几个协议方法,通过返回类型就可以很清楚地知道各自的具体作用。你只需要重载它们,然后 return
一个动画的实例对象,一切都搞定了。使用准则就是:UINavigationController pushViewController
时重载 UINavigationControllerDelegate 的方法;UIViewController presentViewController
时重载 UIViewControllerTransitioningDelegate
的方法。”
——摘录来自: 杨骑滔(KittenYang). “A GUIDE TO IOS ANIMATION”。 iBooks.
实现步骤
1.根据第一小节中提到的关于转场动画的解释,是说我们在当天起始跳转控制器中实现对应的
push
或者present
对应的代理方法.
2.创建继承自 NSObject 并且声明 UIViewControllerAnimatedTransitioning 的的动画类
3.重载 UIViewControllerAnimatedTransitioning 中的协议方法。
就这三步. 具体的转场效果,在第3步中自行定义,你写成啥样的,他就按照给你样转
案例分析
再回到我们这个案例.这个效果,其实是两个有形状的UIBezierPath的贝塞尔曲线对象的path
值,分别作为CABasicAnimation对象的起始值到终点值. 然后系统内部发生的变化. 参看下边代码:
maskLayerAnimation.fromValue = (__bridge id)(maskStartBP.CGPath);
maskLayerAnimation.toValue = (__bridge id)((maskFinalBP.CGPath));
杨骑滔在animateTransition:
方法中,首先获取到跳转和跳转到的控制器,然后把这两个控制器的view添加到transitionContext.containerView
中,接着创建两个圆形的UIBezierPath对象,最终的转成效果类似我们案例一.实现代码也有类似的地方.
其中,第一个需要注意的地方是:触发点的判断,判断在哪个象限,然后得出出发点的坐标,如果你对象限有点遗忘的话,你可以看下边这幅图,马上就想起来了:
http://blog.csdn.net/ys410900345/article/details/42924827
/** timingFunction
*
* 用于变化起点和终点之间的插值计算,形象点说它决定了动画运行的节奏,比如是均匀变化(相同时间变化量相同)还是
* 先快后慢,先慢后快还是先慢再快再慢.
*
* 动画的开始与结束的快慢,有五个预置分别为(下同):
* kCAMediaTimingFunctionLinear 线性,即匀速
* kCAMediaTimingFunctionEaseIn 先慢后快
* kCAMediaTimingFunctionEaseOut 先快后慢
* kCAMediaTimingFunctionEaseInEaseOut 先慢后快再慢
* kCAMediaTimingFunctionDefault 实际效果是动画中间比较快.
*/