一、CALayer常用属性:
属性 | 说明 | 是否支持隐式动画 |
---|---|---|
anchorPoint | 和中心点position重合的一个点,称为“锚点”,锚点的描述是相对于x、y位置比例而言的默认在图像中心点(0.5,0.5)的位置 | 是 |
backgroundColor | 图层背景颜色 | 是 |
borderColor | 边框颜色 | 是 |
borderWidth | 边框宽度 | 是 |
bounds | 图层大小 | 是 |
contents | 图层显示内容,例如可以将图片作为图层内容显示 | 是 |
contentsRect | 图层显示内容的大小和位置 | 是 |
cornerRadius | 圆角半径 | 是 |
doubleSided | 图层背面是否显示,默认为YES | 否 |
frame | 图层大小和位置,不支持隐式动画,所以CALayer中很少使用frame,通常使用bounds和position代替 | 否 |
hidden | 是否隐藏 | 是 |
mask | 图层蒙版 | 是 |
maskToBounds | 子图层是否剪切图层边界,默认为NO | 是 |
opacity | 透明度 ,类似于UIView的alpha | 是 |
position | 图层中心点位置,类似于UIView的center | 是 |
shadowColor | 阴影颜色 | 是 |
shadowOffset | 阴影偏移量 | 是 |
shadowOpacity | 阴影透明度,注意默认为0,如果设置阴影必须设置此属性 | 是 |
shadowPath | 阴影的形状 | 是 |
shadowRadius | 阴影模糊半径 | 是 |
sublayers | 子图层 | 是 |
sublayerTransform | 子图层形变 | 是 |
transform | 图层形变 | 是 |
- 在CALayer中很少使用frame属性,因为frame本身不支持动画效果,通常使用bounds和position代替。
- CALayer中透明度使用opacity表示而不是alpha;中心点使用position表示而不是center。
- MasksToBounds=YES之后,阴影不起作用,可以在其下面再添加一层阴影图层,实现圆角加阴影效果。
-
CAAnimation和CALayer是键值编码适应的容器类,容器类的意思是你可以为任意的键设置值。即使有些键在CALayer中没有声明,你仍然可以像下面一样设置值:
[theLayer setValue:@50 forKey:@”someKey”];
你可以像检索其他键路径一样检索任意键的值。比如为了检索之前设置的someKey键的值,可以像下面代码一样操作:
someKeyValue = [theLayer valueForKey:@”someKey”];
CAAnimation:核心动画的基础类,不能直接使用,负责动画运行时间、速度的控制,本身实现了CAMediaTiming协议。
CAPropertyAnimation:属性动画的基类(通过属性进行动画设置,注意是可动画属性),不能直接使用。
CAAnimationGroup:动画组,动画组是一种组合模式设计,可以通过动画组来进行所有动画行为的统一控制,组中所有动画效果可以并发执行。
CATransition:转场动画,主要通过滤镜进行动画效果设置。
CABasicAnimation:基础动画,通过属性修改进行动画参数控制,只有初始状态和结束状态。
CAKeyframeAnimation:关键帧动画,同样是通过属性进行动画参数控制,但是同基础动画不同的是它可以有多个状态控制。
(1)、CABasicAnimation:CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"];
basicAnimation.delegate=self;
[basicAnimation setValue:[NSValue valueWithCGPoint:location] forKey:@"endLocation"];
//支持键值编码
basicAnimation.fromValue=[NSValue valueWithCGPoint:_layer.position];
basicAnimation.toValue=[NSValue valueWithCGPoint:location];
basicAnimation.duration=.3;
// basicAnimation.removedOnCompletion=FALSE;
// basicAnimation.fillMode=kCAFillModeBoth;
// fillMode的作用就是决定当前对象过了非active时间段的行为. 比如动画开始之前,动画结束之后。如果是一个动画CAAnimation,则需要将其removedOnCompletion设置为NO,要不然fillMode不起作用.
// kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
// kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
// kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始.你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态
// kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态.
[_layer addAnimation:basicAnimation forKey:@"positionAnimation"];
关于动画keyPath:
transform.scale =比例转换
transform.scale.x =阔的比例转换
transform.scale.y =高的比例转换
transform.rotation.z =平面图的旋转
opacity =透明度
margin、zPosition、backgroundColor、cornerRadius、borderWidth、bounds、contents、contentsRect、cornerRadius、frame、hidden、mask、masksToBounds、opacity、position、shadowColor、shadowOffset、shadowOpacity、shadowRadius、
(2)、CAKeyframeAnimation:
关键帧分两种类型://第一种方式:关键值
CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
NSArray *values=@[[NSValue valueWithCGPoint:_layer.position],
[NSValue valueWithCGPoint:CGPointMake(150, 140)],
[NSValue valueWithCGPoint:CGPointMake(120, 160)],
[NSValue valueWithCGPoint:CGPointMake(150, 200)],
[NSValue valueWithCGPoint:location]];
keyframeAnimation.values=values;
NSArray *times=@[[NSNumber numberWithFloat:.0],
[NSNumber numberWithFloat:.3],
[NSNumber numberWithFloat:.6],
[NSNumber numberWithFloat:.8],
[NSNumber numberWithFloat:1.0]];
keyframeAnimation.keyTimes=times;
keyframeAnimation.duration=4.0;
[_layer addAnimation:keyframeAnimation forKey:@"keyAnimation"];</span>
//第二种方式:关键路径
CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
CGMutablePathRef pathRef = CGPathCreateMutable();
CGPathMoveToPoint(pathRef, NULL, _layer.position.x, _layer.position.y);
CGPathAddCurveToPoint(pathRef, NULL, 100, 300, 250, 300, 175, 480);
keyframeAnimation.path=pathRef;
NSArray *times=@[[NSNumber numberWithFloat:.0],
[NSNumber numberWithFloat:.3],
[NSNumber numberWithFloat:.6],
[NSNumber numberWithFloat:.8],
[NSNumber numberWithFloat:1.0]];
keyframeAnimation.keyTimes=times;
keyframeAnimation.duration=4.0;
keyframeAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
/** Timing function names. **/
/*
CA_EXTERN NSString * const kCAMediaTimingFunctionLinear //直线匀速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionEaseIn //减速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionEaseOut //加速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionEaseInEaseOut //先减速再加速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionDefault //默认
__OSX_AVAILABLE_STARTING (__MAC_10_6, __IPHONE_3_0);
*/
// keyframeAnimation.calculationMode=kCAAnimationDiscrete;
/*
CA_EXTERN NSString * const kCAAnimationLinear
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAAnimationDiscrete
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAAnimationPaced
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAAnimationCubic
__OSX_AVAILABLE_STARTING (__MAC_10_7, __IPHONE_4_0);
CA_EXTERN NSString * const kCAAnimationCubicPaced
__OSX_AVAILABLE_STARTING (__MAC_10_7, __IPHONE_4_0);
*/
[_layer addAnimation:keyframeAnimation forKey:@"keyAnimation"];
(3)、CAAnimationGroup:
- (CABasicAnimation *)scaleAnimaion
{
CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
basicAnimation.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeScale(transformScale, transformScale, 1)];
return basicAnimation;
}
- (CABasicAnimation *)rotationAnimation
{
CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3];
return basicAnimation;
}
- (void)groupAnimation
{
CABasicAnimation *scaleAnimation=[self scaleAnimaion];
CABasicAnimation *rotationAnimation=[self rotationAnimation];
CAAnimationGroup *groupAnimation=[CAAnimationGroup animation];
groupAnimation.animations=@[scaleAnimation,rotationAnimation];
groupAnimation.duration=animationTime;
groupAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
groupAnimation.autoreverses=true;
groupAnimation.repeatCount=HUGE_VALF;
[_layer addAnimation:groupAnimation forKey:@"groupAnimation"];
_start=YES;
}
(4)、CATransition:
CATransition *transition =[[CATransition alloc]init];
transition.type=kCATransitionMoveIn;
//对于苹果官方没有公开的动画类型,只能用字符串来表示,并没有常量定义。// transition.type=@"cube"; transition.type=kCATransitionMoveIn ; transition.subtype=kCATransitionFromRight; [_imgView.layer addAnimation:transition forKey:@"Transition"];
动画类型 | 说明 | 对应常量 | 是否支持方向设置 |
---|---|---|---|
公开API | |||
fade | 淡出效果 | kCATransitionFade | 是 |
movein | 新视图移动到旧视图上 | kCATransitionMoveIn | 是 |
push | 新视图推出旧视图 | kCATransitionPush | 是 |
reveal | 移开旧视图显示新视图 | kCATransitionReveal | 是 |
私有API | 私有API只能通过字符串访问 | ||
cube | 立方体翻转效果 | 无 | 是 |
oglFlip | 翻转效果 | 无 | 是 |
suckEffect | 收缩效果 | 无 | 否 |
rippleEffect | 水滴波纹效果 | 无 | 否 |
pageCurl | 向上翻页效果 | 无 | 是 |
pageUnCurl | 向下翻页效果 | 无 | 是 |
cameralIrisHollowOpen | 摄像头打开效果 | 无 | 否 |
cameraIrisHollowClose | 摄像头关闭效果 | 无 | 否 |
另外对于支持方向设置的动画类型还包含子类型:
动画子类型 | 说明 |
---|---|
kCATransitionFromRight | 从右侧转场 |
kCATransitionFromLeft | 从左侧转场 |
kCATransitionFromTop | 从顶部转场 |
kCATransitionFromBottom | 从底部转场 |
注:可以实现无限循环图片浏览器。
三、动画相关重点:
(1)、CATransaction :
区分隐式动画和隐式事务:隐式动画通过隐式事务实现动画 。
区分显式动画和显式事务:显式动画有多种实现方式,显式事务是一种实现显式动画的方式。
除显式事务外,任何对于CALayer属性的修改,都是隐式事务.这样的事务会在run-loop中被提交.
//设置变化动画过程是否显示,默认为YES不显示
[CATransaction setDisableActions:NO];
//设置圆角
layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
//设置透明度
layer.opacity = (layer.opacity == 1.0f) ? 0.5f : 1.0f;
显示事务通过明确的调用begin,commit来提交动画
[CATransaction begin];
[CATransaction begin];
[CATransaction setDisableActions:YES];
layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
[CATransaction commit];
//上面的动画并不会立即执行,需要等最外层的commit
[NSThread sleepForTimeInterval:10];
//显式事务默认开启动画效果,kCFBooleanTrue关闭
[CATransaction setValue:(id)kCFBooleanFalse
forKey:kCATransactionDisableActions];
//动画执行时间
[CATransaction setValue:[NSNumber numberWithFloat:10.0f] forKey:kCATransactionAnimationDuration];
//[CATransaction setAnimationDuration:[NSNumber numberWithFloat:5.0f]];
anotherLayer.cornerRadius = (anotherLayer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
[CATransaction commit];
(2)、动画暂停与继续:
- (IBAction)continueAnimation:(id)sender {
if (_layer.speed==0) {
CFTimeInterval beginTime=CACurrentMediaTime()-_layer.timeOffset;
_layer.timeOffset=0;
_layer.beginTime=beginTime;
_layer.speed=1;
}
}
- (IBAction)pauseAnimation:(id)sender {
if (_layer.speed==1) {
_layer.timeOffset=[_layer convertTime:CACurrentMediaTime() fromLayer:nil];
_layer.speed=0;
}
}
(3)、动画定时器:- (void)viewDidLoad {
[super viewDidLoad];
_index=0;
CADisplayLink *displayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(bgColorChange:)];
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// Do any additional setup after loading the view.
}
-(void)bgColorChange:(CADisplayLink *)displayLink
{
_index++;
if (_index==400) {
[displayLink invalidate];
}
int value_r=arc4random()%255;
int value_g=arc4random()%255;
int value_b=arc4random()%255;
self.view.backgroundColor=[UIColor colorWithRed:value_r/255.0 green:value_g/255.0 blue:value_b/255.0 alpha:1];
}
(4)、drawRect:与drawLayer:inContext、drawInContext:
KCALayer.m文件
#import "KCALayer.h"
@implementation KCALayer
- (void)drawInContext:(CGContextRef)ctx
{
NSLog(@"3-drawInContext:");
NSLog(@"CGContext:%@",ctx);
}
@end
KCView.m文件
#import "KCView.h"
#import "KCALayer.h"
@implementation KCView
- (instancetype)initWithFrame:(CGRect)frame
{
if (self=[super initWithFrame:frame]) {
KCALayer *layer=[[KCALayer alloc]init];
layer.bounds=CGRectMake(0, 0, 185, 185);
layer.position=CGPointMake(160, 284);
layer.backgroundColor=[UIColor colorWithRed:0 green:146/255.0 blue:1.0 alpha:1.0].CGColor;
[layer setNeedsDisplay];
[self.layer addSublayer:layer];
}
return self;
}
-(void)drawRect:(CGRect)rect{
NSLog(@"2-drawRect:");
NSLog(@"CGContext:%@",UIGraphicsGetCurrentContext());//得到的当前图形上下文正是drawLayer中传递的
[super drawRect:rect];
}
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
NSLog(@"1-drawLayer:inContext:"); NSLog(@"CGContext:%@",ctx);[super drawLayer:layer inContext:ctx];
@end
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
// NSLog(@"%@",layer);//这个图层正是上面定义的图层
UIImage *image=[UIImage imageNamed:@"touxiang.jpg"];
//注意这个位置是相对于图层而言的不是屏幕
CGContextDrawImage(ctx, CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT), image.CGImage);
}
layer.contents = (id)[UIImage imageNamed:@"view_BG.png"].CGImage; // 给图层添加背景图片
drawInContext