相关资源
GitHub粒子发射和复制图层示例
GitHub粘性控件示例
GitHub弹性动画
CALayer分析
响应者手势分析
CAEmitter分析
QuartzCore 简介
本文档集合提供了核心动画的API参考。核心动画为应用程序提供动画和显示层次结构功能。有关详细信息,请参见 Core Animation Programming Guide。
QuartzCore主要结构
- CoreAnimation
- CADisplayLink定时器
- CALayer 及其子类(参考上方链接)
- CAMediaTiming协议相关
- CATransaction事物相关
- CATransform3D
可以看出所有的类和协议都以CA开头,所以可以把此框架认为就是核心动画框架
CoreAnimation简介
核心动画本身并不是绘图系统。它是一个在硬件层面合成和操纵您的应用程序的内容的基础设施。在此基础设施的核心是CALayer对象,层用于管理和操作内容。一个图层捕获你的内容到一个位图中,位图可以很容易地被图形硬件使用。在大多数应用中,层是用来管理View内容的,但也可以根据需要创建独立独立的层使用。
CoreAnimation基本使用思路
其实还有一个孙子类CASpringAnimation,它继承自CABasicAnimation,是用来做弹性动画的。其实很多动画UIKit中也有相关的API(包括弹性动画),至于使用哪一种动画:
- UIView动画与核心动画的区别?
- 核心动画只作用在layer.
- 核心动画修改的值都是假像.它的真实位置没有发生变化,不会改变layer的frame、transform属性.
- 什么时候用UIView动画什么时候用核心动画?
- 当需要与用户进行交互时用UIView,不需要与用户进行交互时两个都可以。
- 什么情况用核心动画最多?
- 转场动画(UIView的转场动画类型比较少).
- 帧动画.
- 动画组.
CAAnimation使用
所有的核心动画形式都定义在这个CAAnimation.h头文件中
开发步骤:
- 首先得有CALayer(因为CoreAnimation是作用在CALayer上的
- 初始化一个CAAnimation对象,并设置一些动画相关属性
- 通过调用CALayer的addAnimation:forKey:方法,增加CAAnimation对象到CALayer中,这样就能开始执行动画了
- 通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画
CAMediaTiming协议
简介:这个协议对于核心动画很重要。它提供对动画节奏时间的控制的API。 Layers and Animations都遵守并实现了协议方法。这个协议建立了分层的定时系统定时系统,每个对象描述的时间值都是映射自其parent。
Tip:animation的parent是groupAnimation,再往上是UILayer,再往上是layer.superLayer。下面会举例一个属性分析。
CAMediaTiming属性
/* 动画开始的时间,所有类型对象的该值都是0,它好像是一个相对值:举例:假如layer.beginTime = 1,图层上的动画animation.beginTime = CACurrentMediaTime() + 2 ,那么这个动画被加入之后就会延迟1+2=3秒钟开始执行*/
@property CFTimeInterval beginTime;
/* Specifies the basic duration of the animation, in seconds. */
@property CFTimeInterval duration;
/* 运动速度,如果该值是2,那么该动画的速度将会是parent类的2倍 默认值是 1*/
@property float speed;
/*timeOffset和beginTime类似,但是和增加beginTime导致的延迟动画不同,增加timeOffset只是让动画快进到某一点,例如,对于一个持续1秒的动画来说,设置timeOffset为0.5意味着动画将从一半的地方开始。默认值0 */
@property CFTimeInterval timeOffset;
/* The repeat count of the object. May be fractional. Defaults to 0. */
@property float repeatCount;
/* The repeat duration of the object. Defaults to 0. */
@property CFTimeInterval repeatDuration;
/* 反向执行动画. Defaults to NO. */
@property BOOL autoreverses;
/* 动画执行完事之后,应该怎么处理,如下选项
CA_EXTERN NSString * const kCAFillModeForwards
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAFillModeBackwards
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAFillModeBoth
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAFillModeRemoved
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
Defaults to 'removed'. */
@property(copy) NSString *fillMode;
CACurrentMediaTime()
Returns the current CoreAnimation absolute time.
这个确实不好理解,不过我们可以通过测试总结:
- 他从动画产生被添加到Layer上记录一个时间a;
- 如果动画是被beginTime 延迟了2秒,但是它的值是a+=2;
- 如果动画被暂停了3(speed = 0),a还是会按系统时钟走下去a+=3;
所以CACurrentMediaTime()这个时间非常关键
CALayer上动画的暂停和恢复
- (void)pauseLayer {
CALayer *layer = self.redView.layer;
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
// 让CALayer的时间停止走动
layer.speed = 0.0;
// 让CALayer的时间停留在pausedTime这个时刻
layer.timeOffset = pausedTime;
}
- (void)resumeLayer {
CALayer *layer = self.redView.layer;
CFTimeInterval pausedTime = layer.timeOffset;
// 1. 让CALayer的时间继续行走
layer.speed = 1.0;
// 2. 取消上次记录的停留时刻
layer.timeOffset = 0.0;
// 3. 计算暂停的时间(这里也可以用CACurrentMediaTime()-pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
// 4. 设置相对于父坐标系的开始时间(往后退timeSincePause)
NSLog(@"Resume---- %f",timeSincePause);
layer.beginTime += timeSincePause;
}
CAAnimation
是所有核心动画对象的父类
/* 动画节奏控制,默认线性动画 */
@property(nullable, strong) CAMediaTimingFunction *timingFunction;
/* 动画执行过程代理 */
@property(nullable, strong) id <CAAnimationDelegate> delegate;
/*动画执行完毕是否从Layer上移除,默认YES;如果不想移除动画最终状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
*/
@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;
// CAAnimationDelegate方法(可选)
/* Called when the animation begins its active duration. */
- (void)animationDidStart:(CAAnimation *)anim;
/* 当动画完成了它的执行时间或者被移除了,这个方法会被调用. 'flag'is true if the animation reached the end of its active duration
without being removed. */
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
CAPropertyAnimation
CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation
/* 通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。比如,指定@“position”为keyPath,就修改CALayer的position属性的值,以达到平移的动画效果 */
@property(nullable, copy) NSString *keyPath;
CABasicAnimation
// keyPath相应属性的初始值
@property(nullable, strong) id fromValue;
// keyPath相应属性的结束值
@property(nullable, strong) id toValue;
/ /keyPath相应属性的过渡值
@property(nullable, strong) id byValue;
CAKeyframeAnimation
关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是:CAKeyframeAnimation对keyPath可以使用多值,而且支持路线Path
// 里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧。
@property(nullable, copy) NSArray *values;
/* 可选属性,定义了动画功能的行为,非空值就会覆盖Values属性*/
@property(nullable) CGPathRef path;
/* 可选,定义了动画的节奏(NSNumber类型)。每个值对应values里的每一个值,取值[0,1]。比如:values中有三个值,keyTimes = @[@0.2,@0.5,@0.8],则在duration*0.2开始从value0执行动画,在duration*0.9到value2并等待uration*0.1时间之后结束动画 */
@property(nullable, copy) NSArray<NSNumber *> *keyTimes;
// 对应values,加入values有n个keyframes,那么就需要n-1个timingFunctions,它描述keyframe到keyframe的时间节奏。
@property(nullable, copy) NSArray<CAMediaTimingFunction *> *timingFunctions;
CASpringAnimation
弹性动画,继承CABasicAnimation
/* 附在弹簧末端的物体的质量。必须大于0,默认值是1. */
@property CGFloat mass;
/* 弹簧刚度系数。必须大于0, Defaults to 100. */
@property CGFloat stiffness;
/* 阻尼系数, 必须大于或者等于0,Defaults to 10. */
@property CGFloat damping;
/* 附在弹簧上的物体的初速度,默认值0,代表没有移动;负值表示网固定点反方向运动,正值反之 */
@property CGFloat initialVelocity;
/* 返回弹簧系统在静止时所需的估计时间。 时间是在当前系数下预估的。 */
@property(readonly) CFTimeInterval settlingDuration;
CAAnimationGroup
动画组,动画组,是CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行,属性beginTime刚才也提到了,具有累加的效果。
CATransition
转场动画,CATransition是CAAnimation的子类,用于做转场动画。UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果。
/* 转场动画类型,Defaults to `fade'. */
@property(copy) NSString *type;
/* 转场动画子类型 */
@property(nullable, copy) NSString *subtype;
/* The amount of progress through to the transition at which to begin and end execution. Legal values are numbers in the range [0,1]。endProgress(默认值1)值必须要大于startProgress(默认值0)。*/
@property float startProgress;
@property float endProgress;
/* 执行过度的可选过滤器,一旦设置`type' and `subtype'设置被忽略. The filter must implement `inputImage', `inputTargetImage' and `inputTime' input keys, and the `outputImage' output key. Optionally it may support the `inputExtent' key, which will be set to a rectangle describing the region in which the transition should run. Defaults to nil. */
@property(nullable, strong) id filter;