CALayer和核心动画

iOS里面一个View的可见是因为内部的一个CALayer类型的layer属性,能够响应事件是因为继承了UIResponder类。当UIView需要显示在屏幕上的时候会调用drawRect:方法进行

绘图,绘图完毕后系统会将图层拷贝到屏幕上,完成显示。

 

通过操作CALayer对象可以很方便的操作UIView的一些外观属性,还可以给图层添加动画来实现一些比较炫酷的效果。

常用的属性包含以下:@property CGRect bounds; 

复制代码
/* 宽高 The position in the superlayer that the anchor point of the layer's
 * bounds rect is aligned to. Defaults to the zero point. Animatable. */

@property CGPoint position;
/* 中心位置,The Z component of the layer's position in its superlayer. Defaults
 * to zero. Animatable. */
@property CGPoint anchorPoint;
/* 
这个属性比较重要,锚点决定了那layer的某个点出现在position的位置。

The Z component of the layer's anchor point (i.e. reference point for * position and transform). Defaults to zero. Animatable.
*/ @property(nullable) CGColorRef backgroundColor;

/* 背景颜色
When positive, the background of the layer will be drawn with * rounded corners. Also effects the mask generated by the * `masksToBounds' property. Defaults to zero. Animatable.
*/ @property CGFloat cornerRadius; /*
切圆角
The width of the layer's border, inset from the layer bounds. The * border is composited above the layer's content and sublayers and * includes the effects of the `cornerRadius' property. Defaults to * zero. Animatable.
*/ @property CGFloat borderWidth; /* The color of the layer's border. Defaults to opaque black. Colors * created from tiled patterns are supported. Animatable. */ @property(nullable) CGColorRef borderColor; /* The opacity of the layer, as a value between zero and one. Defaults * to one. Specifying a value outside the [0,1] range will give undefined * results. Animatable. */
复制代码

当设置某些控件发现圆角不起作用的时候要考虑,控件不仅仅有一个layer,显示内容不是在主层上面,应该考虑 self.myView.layer.masksToBounds设置为YES,使得超过主层的部分给清除,但是操作这里的时候阴影自然也就被清除了,如果要保证既有阴影,又无压力的切圆角,可以采用其他措施,比如可以用Quartz 2D方法生成一个圆角的图片然后再用。

layer支持3D效果的旋转,第一个参数表示旋转的角度,后面3个是xyz的坐标,表示沿着从原点到坐标(xyz)所在的直线的轴进行旋转,如果依然想沿着手机屏幕旋转只需要沿着z轴旋转就可以了,

 

layer的创建

1.直接使用CALayer创建

复制代码
    CALayer *layer = [CALayer layer];
    layer.backgroundColor = [UIColor redColor].CGColor;
    layer.bounds = CGRectMake(0, 0, 100, 100);
    layer.position = CGPointMake(200, 100);
    layer.cornerRadius = 10;
    layer.masksToBounds = YES;
    //这个属性是id类型,可以添加的不仅仅是image
    layer.contents = (id)[UIImage imageNamed:@"one"].CGImage;
    [self.view.layer addSublayer:layer];
复制代码

 

上面这种创建的layer无需强制调用setNeedsDisplay方法就可以显示。

@property(nullable, weak) id delegate;

这是layer的代理的定义,是一个id类型的,表示任何类都可以当成他的代理,而且任何类都已经存在他的代理方法。只要在代理类重写下面方法后,然后layer再调用

setNeedsDisplay,就可以自动调用下面的方法实现绘图功能,

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx

2.自己定义的layer继承CALayer。

这个时候要在自定义的layer类里面在下面方法添加代码

- (void)drawInContext:(CGContextRef)ctx

的ctx参数就是当前图层的上下文,在UIView里面的drawRect 方法里面常常用来绘制当前view的图层,需要下面代码来获取上下文

CGContextRef ctx =  UIGraphicsGetCurrentContext(); 

通过自定义继承的图层使用的时候,

 

CALayer的隐式动画

每个UIView内部都有一个CALayer,所有的手动创建的CALayer对象(非创建View的时候带的layer),当对他的部分属性进行修改的时候默认会产生一些动画效果,这些属性称为

 

复制代码
//    [CATransaction begin]; // 开启事务
//    [CATransaction setDisableActions:YES];
 
//这里修改会触发隐式动画的属性将不再触发隐式动画
        
//    [CATransaction commit]; // 提交事务
复制代码

 

 

Core Animation(核心动画)

除了隐式动画外,CALayer可以手动的添加动画,动画是一个类,只要要创建一个动画,然后设置该动画的属性,把动画添加到图层上就能实现动画效果

CALayer中很多属性都可以通过CAAnimation实现动画效果,包括:opacity、position、transform、bounds、contents等(可以在API文档中搜索:CALayer Animatable Properties) 通过调用CALayer的addAnimation:forKey增加动画到层(CALayer)中,这样就能触发动画了。通过调用removeAnimationForKey可以停止层中的动画 Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。

一共有4种常用的动画类,继承了CAAnimation,CAAnimation是抽象类,不能直接使用,继承结构如下:

 

所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类

属性解析:(红色代表来自CAMediaTiming协议的属性)

duration:动画的持续时间

repeatCount:动画的重复次数

repeatDuration:动画的重复时间

removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards

fillMode:决定当前对象在非active时间段的行为.比如动画开始之前,动画结束之后

beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当前时间

timingFunction:速度控制函数,控制动画运行的节奏

delegate:动画代理

 主要的步骤就是:

 

初始化一个动画对象,并设置一些动画的相关属性,添加动画到层中,开始执行动画。

CABasicAnimation

复制代码
//移动
- (void)testTransform
{
    // 1.创建动画对象
    CABasicAnimation *anim = [CABasicAnimation animation];
    
    // 2.设置动画对象
    // keyPath决定了执行怎样的动画, 调整哪个属性来执行动画
    //    anim.keyPath = @"transform.rotation";
    //    anim.keyPath = @"transform.scale.x";
    anim.keyPath = @"transform.translation.x";
    anim.toValue = @(100);
    //    anim.toValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
    anim.duration = 2.0;
    
    anim.removedOnCompletion = NO;
    anim.fillMode = kCAFillModeForwards;
    
    // 3.添加动画
    [self.layer addAnimation:anim forKey:nil];
}
//旋转
- (void)testRotate
{
    // 1.创建动画对象
    CABasicAnimation *anim = [CABasicAnimation animation];
    // 2.设置动画对象
    // keyPath决定了执行怎样的动画, 调整哪个属性来执行动画
    anim.keyPath = @"transform";
    //    anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
    anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, -1, 0)];
    anim.duration = 2.0;
    
    anim.removedOnCompletion = NO;
    anim.fillMode = kCAFillModeForwards;
    
    // 3.添加动画
    [self.layer addAnimation:anim forKey:nil];
}
//缩放
- (void)testScale
{
    // 1.创建动画对象
    CABasicAnimation *anim = [CABasicAnimation animation];
    
    // 2.设置动画对象
    // keyPath决定了执行怎样的动画, 调整哪个属性来执行动画
    anim.keyPath = @"bounds";
    //    anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
    anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)];
    anim.duration = 2.0;
    
    /**让图层保持动画执行完毕后的状态**/
    // 动画执行完毕后不要删除动画
    anim.removedOnCompletion = NO;
    // 保持最新的状态
    anim.fillMode = kCAFillModeForwards;
    
    // 3.添加动画
    [self.layer addAnimation:anim forKey:nil];
}

//移动
- (void)testTranslate
{
    // 1.创建动画对象
    CABasicAnimation *anim = [CABasicAnimation animation];
    
    // 2.设置动画对象
    // keyPath决定了执行怎样的动画, 调整哪个属性来执行动画
    anim.keyPath = @"position";
    //    anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
    // toValue : 最终变成什么值
    // byValue : 增加多少值
    anim.byValue = [NSValue valueWithCGPoint:CGPointMake(200, 200)];
    anim.duration = 2.0;
    
    /**让图层保持动画执行完毕后的状态**/
    // 动画执行完毕后不要删除动画
    anim.removedOnCompletion = NO;
    // 保持最新的状态
    anim.fillMode = kCAFillModeForwards;
    
    // 3.添加动画
    [self.layer addAnimation:anim forKey:nil];
}
复制代码

 

 CAKeyframeAnimation

 CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasic Animation只能从一个数值(fromValue)变到另一个数值(toValue),CAKeyframeAnimation会使用一个NSArray保存这些数值。

values:就是上述的NSArray对象。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧

path:可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的anchorPoint和position起作用。如果你设置了path,那么values将被忽略

keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是

平分的 CABasicAnimation可看做是最多只有2个关键帧的CAKeyframeAnimation

复制代码
//抖动效果
- (void)shake {
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    
    float angle = angle2radian(3);
    
    anim.values = @[@(-angle), @(angle), @(-angle)];
    
    anim.duration = 0.2;
    
    anim.repeatCount = MAXFLOAT;
    
    [self.myview.layer addAnimation:anim forKey:nil];
}
//移动
- (void)translate2 {
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 0, 300, 300));
    anim.duration = 2;
    anim.path = path;
    
    [self.myview.layer addAnimation:anim forKey:nil];
    
    CGPathRelease(path);
}
//移动
- (void)translate {
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    // 设置动画执行的一个节奏
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    anim.duration = 2;
    
    NSValue *p1 = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
    NSValue *p2 = [NSValue valueWithCGPoint:CGPointMake(300, 0)];
    NSValue *p3 = [NSValue valueWithCGPoint:CGPointMake(300, 300)];
    NSValue *p4 = [NSValue valueWithCGPoint:CGPointMake(0, 300)];
    
    anim.values = @[p1, p2, p3, p4];
    
    [self.myview.layer addAnimation:anim forKey:nil];
} 
复制代码
 

CATransition


用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果

type:动画过渡类型

subtype:动画过渡方向

startProgress:动画起点(在整体动画的百分比)

endProgress:动画终点(在整体动画的百分比)

复制代码
    CATransition *anim = [CATransition animation];
    // 动画类型
    anim.type = @"pageCurl";
    // 过渡方向
    anim.subtype = kCATransitionFromRight;
    anim.duration = 0.5;
    [self.imageView.layer addAnimation:anim forKey:nil];
复制代码

   type的意义

  1. pageCurl   向上翻一页  
  2. pageUnCurl 向下翻一页  
  3. rippleEffect 滴水效果  
  4. suckEffect 收缩效果,如一块布被抽走  
  5. cube 立方体效果  
  6. oglFlip 上下翻转效果  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值