CALayer的基本属性
player中有两个重要的属性,position和anchorPoint,position决定位置,假如图层要旋转时anchorPoint则是旋转的点。
假如锚点anchorPoint为默认值即中点(0.5,0.5),而该层的position设置为(0,0)即为父层的左上点,那么该层在父层中只会看到四分之一的部分。
Core Animation结构
其中灰色虚线表示继承关系,红色表示遵守协议。
核心动画中所有类都遵守CAMediaTiming协议。
CAAnaimation是个抽象类,不具备动画效果,必须用它的子类才有动画效果。
CAAnimationGroup和CATransition才有动画效果,CAAnimationGroup是个动画组,可以同时进行缩放,旋转(同时进行多个动画)。
CATransition是转场动画,界面之间跳转(切换)都可以用转场动画。
CAPropertyAnimation也是个抽象类,本身不具备动画效果,只有子类才有。
CABasicAnimation和CAKeyframeAnimation:
CABasicAnimation基本动画,做一些简单效果。
CAKeyframeAnimation帧动画,做一些连续的流畅的动画。
他们的基本使用和现实生活中画画是非常类似的
第1步:准备纸
CALayer *scaleLayer = [[CALayer alloc] init];
scaleLayer.backgroundColor = [UIColor blueColor].CGColor;
scaleLayer.frame = CGRectMake(60, 20, 50, 50);
scaleLayer.cornerRadius = 10;
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleAnimation.autoreverses = YES;
scaleAnimation.fillMode = kCAFillModeForwards;
scaleAnimation.removedOnCompletion = NO;
scaleAnimation.repeatCount = MAXFLOAT;
scaleAnimation.duration = 0.8;
-
kCAFillModeRemoved 默认值为这个,这个是在动画开始前和动画结束后,动画对layer都没有影响,动画结束后恢复到之前的状态
-
kCAFillModeForwards 当前动画结束后,layer会一直保持着最后的状态
-
kCAFillModeBackwards 与kCAFillModeForwards是相对的,就是在动画开始前,将动画加入一个layer,layer便进入动画的初始状态,因为有可能出现fromValue不是目前layer的初始状态的情况,如果fromValue就是layer当前的状态,则这个参数就没太大意义
-
kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态.
下面是手指画出路径之后,layer跟着路径运动的代码
#import "DrawView.h"
@interface DrawView ()
@property (nonatomic, strong) UIBezierPath *path;
@end
@implementation DrawView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// touch
UITouch *touch = [touches anyObject];
// 获取手指的触摸点
CGPoint curP = [touch locationInView:self];
// 创建路径
UIBezierPath *path = [UIBezierPath bezierPath];
_path = path;
// 设置起点
[path moveToPoint:curP];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// touch
UITouch *touch = [touches anyObject];
// 获取手指的触摸点
CGPoint curP = [touch locationInView:self];
[_path addLineToPoint:curP];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// 给imageView添加核心动画
// 添加核心动画
CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
anim.keyPath = @"position";
// anim.values = @[@(angle2Radion(-10)),@(angle2Radion(10)),@(angle2Radion(-10))];
anim.path = _path.CGPath;
anim.duration = 1;
anim.repeatCount = MAXFLOAT;
[[[self.subviews firstObject] layer] addAnimation:anim forKey:nil];
}
- (void)drawRect:(CGRect)rect
{
[_path stroke];
}
@end
转场动画
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 转场代码
if (i == 4) {
i = 1;
}
// 加载图片名称
NSString *imageN = [NSString stringWithFormat:@"%d",i];
_imageView.image = [UIImage imageNamed:imageN];
i++;
// 转场动画
CATransition *anim = [CATransition animation];
anim.type = @"pageCurl";
anim.duration = 2;
[_imageView.layer addAnimation:anim forKey:nil];
}
组动画(第一步准备画纸省略了)
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@
"transform.scale"
];
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleAnimation.autoreverses = YES;
scaleAnimation.repeatCount = MAXFLOAT;
scaleAnimation.duration = 0.8;
CABasicAnimation *moveAnimation = [CABasicAnimation animationWithKeyPath:@
"position"
];
moveAnimation.fromValue = [NSValue valueWithCGPoint:groupLayer.position];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(320 - 80, groupLayer.position.y)];
moveAnimation.autoreverses = YES;
moveAnimation.repeatCount = MAXFLOAT;
moveAnimation.duration = 2;
CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@
"transform.rotation.x"
];
rotateAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotateAnimation.toValue = [NSNumber numberWithFloat:6.0 * M_PI];
rotateAnimation.autoreverses = YES;
rotateAnimation.repeatCount = MAXFLOAT;
rotateAnimation.duration = 2;
CAAnimationGroup *groupAnnimation = [CAAnimationGroup animation];
groupAnnimation.duration = 2;
groupAnnimation.autoreverses = YES;
groupAnnimation.animations = @[moveAnimation, scaleAnimation, rotateAnimation];
groupAnnimation.repeatCount = MAXFLOAT;
将组动画加入到layer上
[groupLayer addAnimation:groupAnnimation forKey:@"groupAnnimation”];
通过步骤基本就对核心动画有了大概了解,下面就开始从头详细说明了
一,clayer(我们的画纸)
主要属性有
@property CGRect bounds;
@property CGPoint position;
@property CGPoint anchorPoint;
@property CGColorRef backgroundColor;
@property CATransform3D transform;
我们通过最后一个属性其实可以直接完成一些简单的动画,但是其动画的时间可能比较迅速,有时候达不到我们要的效果。其实还有一种方法就是通过CADisplayLink
来事实现,我们将transform的尺度缩小,然后通过CADisplayLink可以缓慢的改变。CADisplayLink其实就是一个定时器,是一种以屏幕刷新频率触发的时钟机制,每秒钟执行大约60次左右。
// 定义
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotationChange)];
// 添加到主循环队列
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// 暂停
link.paused = YES;
// 开始
link.paused = NO;
二,CAAnimation(我们的画笔)
CAAnimation是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类
基本属性说明:
duration:动画的持续时间
repeatCount:重复次数,无限循环可以设置HUGE_VALF或者MAXFLOAT
repeatDuration:重复时间
removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode
为kCAFillModeForwards
fillMode:决定当前对象在非active时间段的行为。比如动画开始之前或者动画结束之
beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当前时间
timingFunction:速度控制函数,控制动画运行的节奏
delegate:动画的代理
CAAnimation在分类中定义了代理方法
/* Called when the animation begins its active duration. */
// 动画开始时调用
- (void)animationDidStart:(CAAnimation *)anim;
/* Called when the animation either completes its active duration or
* is removed from the object it is attached to (i.e. the layer). 'flag'
* is true if the animation reached the end of its active duration
* without being removed. */
// 动画结束后调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
CALayer上动画的暂停和恢复
#pragma mark 暂停CALayer的动画
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
// 让CALayer的时间停止走动
layer.speed = 0.0;
// 让CALayer的时间停留在pausedTime这个时刻
layer.timeOffset = pausedTime;
}
#pragma mark 恢复CALayer的动画
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = layer.timeOffset;
// 1. 让CALayer的时间继续行走
layer.speed = 1.0;
// 2. 取消上次记录的停留时刻
layer.timeOffset = 0.0;
// 3. 取消上次设置的时间
layer.beginTime = 0.0;
// 4. 计算暂停的时间(这里也可以用CACurrentMediaTime()-pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
// 5. 设置相对于父坐标系的开始时间(往后退timeSincePause)
layer.beginTime = timeSincePause;
}
CAPropertyAnimation
是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation。
基本属性说明:
属性 | 说明 |
---|---|
keyPath | 通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。比如,指定@“position”为keyPath,就修改CALayer的position属性的值,以达到平移的动画效果 |
CABasicAnimation——基本动画
属性说明:
属性 | 说明 |
---|---|
fromValue | keyPath相应属性的初始值 |
toValue | keyPath相应属性的结束值 |
动画过程说明:
随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue。
keyPath内容是CALayer的可动画Animatable属性。
如果fillMode = kCAFillModeForwards
同时removedOnComletion = NO
,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值
,并没有真正被改变。
CAKeyframeAnimation——关键帧动画
关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别
是:
- CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值
- CABasicAnimation可看做是只有2个关键帧的CAKeyframeAnimation
属性说明:
属性 | 说明 |
---|---|
values | NSArray对象。里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧 |
path | 可以设置一个CGPathRef、CGMutablePathRef,让图层按照路径轨迹移动。path只对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略 |
keyTimes | 可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧。如果没有设置keyTimes,各个关键帧的时间是平分的 |
CAAnimationGroup——动画组
动画组,是CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行。
默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime
属性来更改动画的开始时间。
属性说明:
属性 | 说明 |
---|---|
animations | 用来保存一组动画对象的NSArray |
CATransition——转场动画
CATransition是CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。iOS比Mac OS X的转场动画效果少一点。
UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果。
属性说明:
属性 | 说明 |
---|---|
type | 动画过渡类型 |
subtype | 动画过度方向 |
startProgress | 动画起点(在整体动画的百分比) |
endProgress | 动画终点(在整体动画的百分比) |
过渡效果设置
使用UIView动画函数实现转场动画——双视图
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion;
参数 | 说明 |
---|---|
duration | 动画持续时间 |
option | 动画类型 |
animations | 将改变视图属性的代码放在这个block中 |
completion | 动画结束后,会自动调用这个block |