出处:小码哥大神班5期
CALayer的基本操作
1.CALayer的简介
CALayer又称做层,每个view内部都有一个layer这样的属性。UIView因为CALayer层,才具有显示功能。我们可以通过操作CALayer对象,对UIView进行一些外观属性的调整。比如设置阴影、圆角、边框等。
2.操作layer改变UIView的外观
//设置圆角
view.layer.cornerRadius = 5;
//设置阴影不透明度,默认图层是有阴影的,只不过是透明的
view.layer.shadowOpacity = 1;
//设置阴影圆角
view.layer.shadowRadius = 10;
//设置阴影颜色
view.layer.shadowColor = [UIColor grayColor].CGColor;
//设置阴影位置的偏移量
view.layer.shadowOffset = CGSizeMake(10, 10);
//设置边框
view.layer.borderWidth = 2;
view.layer.borderColor = [UIColor blackColor].CGColor;
效果:
3.操作layer改变UIImageViewView的外观
//设置图片边框
imageV.layer.borderWidth = 2;
imageV.layer.borderColor = [UIColor orangeColor].CGColor;
//设置图片圆角半径
imageV.layer.cornerRadius = 100;
//裁剪超出区域部分的的图片
imageV.layer.masksToBounds = YES;
/*
注:UIImageView当中的ImageView并不是直接添加在层上面的,这是添加在layer当中的
contents里,我们设置所有属性只作用在层上面,对contents里面的东西并不起作用,所有以我们
看不到图片有圆角的效果,可以把maskToBounds这个属性设为yes,
当设为yes,就会把超过根层以外的东西都给裁剪掉。
*/
效果:
4.layer的CATransform3D属性
只有旋转的时候才可以看出3d效果
可以通过kvc的方式进行设置属性,
但是CATransform3DMakeRotation的值是一个结构体,所以用kvc进行设置时要把结构体转成对象
NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
[_imageView.layer setValue:value forKeyPath:@"transform.scale"];
什么时候用kvc
- 当需要做一些快速缩放,平移,二维的旋转是用kvc.
后面forKeyPath属性值不是乱写的,苹果文档当中给了相关的属性。
//平移
[UIView animateWithDuration:1 animations:^{
self.imageV.layer.transform = CATransform3DMakeTranslation(-50, -100, 1);
}];
//缩放
[UIView animateWithDuration:1 animations:^{
[self.imageV.layer setValue:@(0.5) forKeyPath:@"transform.scale"];
}];
//旋转
[UIView animateWithDuration:1 animations:^{
self.imageV.layer.transform =CATransform3DMakeRotation(M_PI , 1, 0, 0);
}];
效果:
自定义CALayer
1.如何自定义layer
自定义CALayer的方式和创建UIView的方式非常相似。
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(50, 50, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer];
//给layer设置图片
layer.contents = (id)[UIImage imageNamed:@"阿狸头像"].CGImage;
2.关于CALayer的疑惑
- 为什么要使用CGImageRef、CGColorRef
为了保证可移植性,QuartzCore不能使用UIImage、UIColor只能使用CGImageRef、CGColorRef
- UIView和CALayer都能够显示图形,该怎么选择?
对比CALayer,UIView多了一个事件处理功能。也就是说CALayer不能处理用户的触摸事件,而UIView可以。所以如果显示的东西需要跟用户进行交互的话,用UIView;如果不需要的话用CALayer;因为CALayer的性能会高一些,因此它少了事件处理功能,更加轻量级。
3.position和anchorpoint
position和anchorpoint是CALayer的两个属性。
以前修改一个空间的位置都是通过frame的方式进行修改。现在利用CALayer的position和anchorpoint也能够修改控件的位置
position:它是用来设置当前的layer在父控件当中的位置的.所以它的坐标原点是以父控件的左上角为坐标原点; anchorpoint:它是决定CALayer身上哪一个会在position属性所指的位置,anchorpoint是以当前的layer左上角为原点;它的取值范围是0~1,默认值是(0.5,0.5)的位置,anchorpoint又称锚点,就是把锚点定到position所指的位置
两者结合使用:想要修改某个控件的位置,可以先设置它的position点,设置完毕后,在设置layer身上的anchorpoint锚点。
4.隐式动画
- 什么是隐式动画
了解什么是隐式动画之前,要先了解什么是根曾和非根层。
根层:UIView内部自动关联着的那个layer,我们称着为根层。
非根层:自己手动创建的层,称着为非根层。
隐式动画就是当非根层的部分属性进行修改时,自动产生的一些动画效果。
- 如何取消隐式动画?
首先要了解动画底层是怎么做的,动画的底层是包装成一个事物来进行的。
什么是事务?
很多操作绑定在一起,当这些操作执行完毕后,才去执行下一个操作。
//开启事务
[CATransaction begin];
//设置事务没有动画
[CATransaction setDisableActions:yes];
//设置动画执行时长
[CATransaction setAnimationDuration:2];
//提交事务
[CATransaction commit];
6.CABasicAnimation基础核心动画
核心动画是作用在层上面的。
动画的本质是改变图层的某一个属性。
CABasicAnimation *anim = [CABasicAnimation animation];
图层有哪些属性,这里才能写哪些属性。
anim.keyPath = @"transform.scale";
anim.toValue = @0.5;
//告诉动画完成时不要移除
anim.removedOnCompletion = NO;
//保存动画最前面的效果
anim.fillMode = kCAFillModeForwards;
//把动画添加到层上面
[view.layer addAnimation:anim forkey:nil];
7.UIView与核心动画的对比
- UIView和核心动画的区别
核心动画只能添加到CALayer
核心动画一切都是假象,并不会改变真实的值。
- 什么时候使用UIView动画
如果需要与用户交互就使用UIView动画。
不需要就使用核心动画
- 什么场景使用核心动画最多
在转场动画中,核心动画的类型比较多。
根据一个路径做动画,只能用核心动画(帧动画)
动画组:同时做多个动画
练习项目
时钟效果
代码:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *clockView;
//秒针的层
@property (weak,nonatomic) CALayer *secondLayer;
//分针的层
@property (weak,nonatomic) CALayer *minuteLayer;
//时针的层
@property (weak,nonatomic) CALayer *hourLayer;
@end
@implementation ViewController
//每一秒转的度数
#define secondA 6
//每一分转的度数
#define minuteA 6
//每一小时要转的度数
#define hourA 30
//角度转弧度
#define angleRad(angle) ((angle)/180 * M_PI)
- (void)viewDidLoad {
[super viewDidLoad];
//每一秒转6度,获取当前多少秒*6得到要转的角度
//添加秒针
self.secondLayer = [self addShiZhenWithHeight:80 width:1 color:[UIColor redColor]];
//添加分针
self.minuteLayer = [self addShiZhenWithHeight:70 width:3 color:[UIColor blackColor]];
//添加时针
self.hourLayer = [self addShiZhenWithHeight:50 width:4 color:[UIColor blackColor]];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
[self timeChange];
}
//添加时针
- (CALayer *)addShiZhenWithHeight:(CGFloat)height width : (CGFloat)width color:(UIColor *)color
{
//实例化一个层
CALayer *layer = [[CALayer alloc] init];
//设置层的大小
layer.frame = CGRectMake(self.clockView.frame.size.width * 0.5, self.clockView.frame.size.height * 0.5, width, height);
//设置层的背景颜色
layer.backgroundColor = color.CGColor;
//设置层的位置
layer.position = CGPointMake(self.clockView.frame.size.width * 0.5, self.clockView.frame.size.height * 0.5);
layer.anchorPoint = CGPointMake(0.5, 1);
// layer.transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
//添加到父层
[self.clockView.layer addSublayer:layer];
return layer;
}
- (void)timeChange
{
//获取系统日历
NSCalendar * calendar = [NSCalendar currentCalendar];
//components:日历单元:年,月,日,时,分,秒
//fromDate:当前的日期
//- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)date;
NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond|NSCalendarUnitMinute|NSCalendarUnitHour fromDate:[NSDate date]];
//获取当前是多少秒
NSInteger curSecond = cmp.second;
//秒针要转的度数
CGFloat curSecondA = curSecond*secondA;
self.secondLayer.transform = CATransform3DMakeRotation(angleRad(curSecondA), 0, 0, 1);
//获取当前是多少分
NSInteger curMinute = cmp.minute;
//分针要转的度数
CGFloat curMinuteA = curMinute * minuteA;
self.minuteLayer.transform = CATransform3DMakeRotation(angleRad(curMinuteA), 0, 0, 1);
//获取当前是几时
NSInteger curHour = cmp.hour;
//时针要转的度数+每改变一分时针要转0.5度
CGFloat curHourA = curHour * hourA + curMinute * 0.5;
self.hourLayer.transform = CATransform3DMakeRotation(angleRad(curHourA), 0, 0, 1);
}