1,CALayer 是什么?
CALayer 我们又称它叫做层. 在每个 UIView 内部都有一个 layer 这样一个属性, UIView 之所以能够显示, 就是因为它里面有这个 layer 才具有显示的功能. 我们可以通过操作 CALayer 对象, 可以很方便地调整 UIView 的一些外观属性, 可以给 UIView 设置阴影, 圆角, 边框等等...
2, 如何操作 layer 改变 UIView 外观?
2.1 设置阴影
- // 默认图层是有阴影的, 只不过, 是透明的
- _RedView.layer.shadowOpacity = 1;
- // 设置阴影的圆角
- _RedView.layer.shadowRadius =10;
- // 设置阴影的颜色, 把 UIKit 转换成 CoreGraphics 框架, 用. CG 开头
- _RedView.layer.shadowColor = [UIColor blueColor].CGColor;
2.2. 设置边框
- // 设置图层边框, 在图层中使用 CoreGraphics 的 CGColorRef
- _RedView.layer.borderColor = [UIColor whiteColor].CGColor;
- _RedView.layer.borderWidth = 2;
2.3. 设置圆角
- // 图层的圆角半径, 圆角半径为宽度的一半, 就是一个圆
- _RedView.layer.cornerRadius = 50;
3, 如何操作 layer 改变 UIImageView 的外观?
- // 设置图形边框
- _imageView.layer.borderWidth = 2;
- _imageView.layer.borderColor = [UIColor whiteColor].CGColor;
- // 设置图片的圆角半径, 必须要进行第二步的裁剪, 超出裁剪区域的部分全部裁剪掉
- _imageView.layer.cornerRadius = 50;
- _imageView.layer.masksToBounds = YES;
注意: 设置图片的圆角时, 除了设置圆角半径, 还必须要进行第二步的裁剪, 设置 masksToBounds 为 yes. 这是因为 UIImageView 当中 Image 并不是直接添加在层上面的, 这是添加在 layer 当中的 contents 里. UIImageView 中是 UIView 的主 layer 上添加了一个次 layer(用来绘制 contents), 我们设置边框的是主 layer, 但是次 layer 在上变, 不会有任何的影响, 所以当我们调用切割语句的时候, 超出边框意外的都被切割了!!
我们设置层的所有属性它只作用在层上面, 对 contents 里面的东西并不起作用, 所以如果我们不进行裁剪, 我们是看不到图片的圆角效果的. 想要让图片有圆角的效果, 就必须把 masksToBounds 这个属性设为 YES, 当设为 YES, 把就会把超过根层以外的东西都给裁剪掉.
4,layer 的 CATransform3D 属性变换
UIView 和 Layer 都有 transform 属性, 但是他们的所属有区别, 类型也有区别
1.picView.transform 是二维的属性, 是 CGAffineTransform 类型
2.picView.layer.transform 是 layer 级别的三维属性, 是 CATransform3D 类型的, 当然也可以做二维的事情, 只有旋转的时候才可以看出 3D 的效果.
- // 旋转 x,y,z 分别代表 x,y,z 轴.
- CATransform3DMakeRotation(M_PI, 1, 0, 0);
- // 平移
- CATransform3DMakeTranslation(x,y,z)
- // 缩放
- CATransform3DMakeScale(x,y,z);
属性设置有三种方法
- //1. 直接使用基本的三维赋值方法
- picView.layer.transform = CATransform3DMakeScale(1, 2.5, 0);
- //2. 使用 KVC 将 CATransform3DMakeScale 生成的对象给 layer
- NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
- [picView.layer setValue:value forKeyPath:@"transform.scale"];
- //3. 使用快捷方法设置属性
- [picView.layer setValue:@5 forKeyPath: "transform.scale.y"];
什么时候用 KVC?
当需要做一些快速缩放, 平移, 二维的旋转时用 KVC. 后面 forKeyPath 属性值不是乱写的, 苹果文档当中给了相关的属性.
比如: [_imageView.layer setValue:@0.5 forKeyPath:@"transform.scale"];
5, 如何自定义 Layer ?
自定义 CALayer 的方式创建 UIView 的方式非常相似.
- // 创建
- CALayer *layer = [CALayer layer];
- // 设置尺寸和位置
- layer.frame = CGRectMake(50, 50, 100, 100);
- // 设置背景
- layer.backgroundColor = [UIColor redColor].CGColor;
- // 给 layer 设置图片.
- layer.contents = (id)[UIImage imageNamed:@"image001"].CGImage;
- // 加载绘制
- [self.view.layer addSublayer:layer];
6, 为什么要使用 CGImageRef,CGColorRef?
为了保证可移植性, QuartzCore 不能使用 UIImage,UIColor, 只能使用 CGImageRef,CGColorRef
7,UIView 和 CALayer 都能够显示东西, 该怎样选择?
在明白要怎么选择之前, 我们先了解一下 UIView 和 layer 的不同点:
在 iOS 中看的见, 摸得着的都是 UIView, 例如一个按钮, UITextField,UILable 等等, 都是 UIView
UIView 之所以能够显示在屏幕上, 是试音 UIView 中有一个图层
在创建 UIView 的时候, 系统会自动创建一个 CALayer 在其中, 用于显示东西, 可以通过 view.layer 来去获取图层属性
当 UIView 要去显示的时候, 先去调用 drawRect 方法, 将要绘制的东西绘制到图层上, 然后拷贝图层, 完成了 UIView 的显示
UIView 只有交互的功能, 没有显示的功能
CALayer 只要显示的功能, 没有交互的功能
UIView 可以做一些简单的动画, 例如: 平移, 拉伸, 旋转
一些比较高端的动画, 都是直接操作 CALayer 的, 可以制作 3D 动画
使用 CALayer, 可以直接操作显示的东西, 例如阴影, 圆角, 边框等
所以, 对比 CALayer,UIView 多了一个事件处理的功能. 也就是说, CALayer 不能处理用户的触摸事件, 而 UIView 可以.
如果显示出来的东西需要跟用户进行交互的话, 用 UIView;
如果不需要跟用户进行交互, 用 UIView 或者 CALayer 都可以, CALayer 的性能会高一些, 因为它少了事件处理的功能, 更加轻量级.
8,position 和 anchorPoint?
position 和 anchorPoint 是 CAlayer 的两个属性, 我们以前修改一个控件的位置都是通过 Frame 的方式进行修改. 现在 CALayer 则是通过 position 和 anchorPoint 属性也能够修改控件的位置,
这两个属性是配合使用的.
position: 它是用来设置当前的 layer 在父控件当中的位置的, 默认它的坐标原点, 以父控件的左上角为 (0.0) 点.
anchorPoint
: 锚点, 就是把锚点定到 position 所指的位置. 它是决点 CALayer 身上哪一个点会在 position 属性所指的位置
,anchorPoint 它是以当前的 layer 左上角为原点 (0.0), 它的取值范围是 0~1, 它的默认在中间也就是(0.5,0.5) 的位置.
两者结合使用, 想要修改某个控件的位置, 我们可以设置它的 position 点. 设置完毕后, layer 身上的 anchorPoint 会自动定到 position 所在的位置.
- // 下面两行代码就是设置 views 的 正中间 坐标(200,200)
- _views.layer.position = CGPointMake(200, 200);
- _views.layer.anchorPoint = CGPointMake(0.5, 0.5);
- // 下面两行代码就是设置 views 的 左上角 坐标(200,200)
- _views.layer.position = CGPointMake(200, 200);
- _views.layer.anchorPoint = CGPointMake(0, 0);
- // 下面两行代码就是设置 views 的 右下角 坐标(200,200)
- _views.layer.position = CGPointMake(200, 200);
- _views.layer.anchorPoint = CGPointMake(1, 1);
9, 隐式动画
9.1 什么是隐式动画?
了解什么是隐式动画, 要先了解是什么根层和非根层:
根层: UIView 内部自动关联着的那个 layer 我们称它是根层.
非根层: 自己手动创建的层, 称为非根层.
隐式动画就是当对非根层的部分属性进行修改时, 它会自动的产生一些动画的效果, 我们称这个默认产生的动画为隐式动画.
9.2 如何取消隐式动画?
首先要了解动画底层是怎么做的, 动画的底层是包装成一个事务来进行的.
什么是事务? 很多操作绑定在一起, 当这些操作执行完毕后, 才去执行下一个操作.
- // 开启事务
- [CATransaction begin];
- // 设置事务没有动画
- [CATransaction setDisableActions:YES];
- // 设置动画执行的时长
- [CATransaction setAnimationDuration:2];
- // 提交事务
- [CATransaction commit];
10, 时钟效果
10.1 搭建界面
界面上时针, 分针, 秒针不需要与用户进行交互, 所以都可以使用 layer 方式来做,
具体时间可以用用一张圆形图片来显示, 然后在这个 imageView 的 layer 中进行时针, 分针和秒针的绘制.
做之前要观察时针在做什么效果. 是根据当前的时间, 绕着表盘的中心点进行旋转.
要了解一个非常重要的知识点, 无论是旋转, 缩放它都是绕着锚点进行的.
要想让时针, 分针, 称针显示的中间, 还要绕着中心点进行旋转,
那就要设置它的 position 和 anchorPoint 两个属性.
- // 添加秒针
- - (void)addSecond{
- // 创建秒针
- CALayer *layer = [CALayer layer];
- _secondL = layer;
- // 设置宽高
- layer.bounds = CGRectMake(0, 0, 1, 80);
- // 设置锚点为秒针的 x 轴中心, y 轴最右端, 该锚点的位置是时钟图片的正中心
- layer.anchorPoint = CGPointMake(0.5, 1);
- layer.position = CGPointMake(_clockView.bounds.size.width * 0.5, _clockView.bounds.size.height * 0.5);
- // 设置秒针的颜色
- layer.backgroundColor = [UIColor redColor].CGColor;
- // 将秒针的 layer 添加到时钟图片的 layer 中
- [_clockView.layer addSublayer:layer];
- }
- // 时针, 分针的添加方式类似, 只是设置的宽高有点区别, 不再贴出来
10.2 让秒针开始旋转.
- // 角度转换成弧度
- #define angle2Rad(angle) ((angle) / 180.0 * M_PI)
- // 每一秒 秒针 旋转 6 度
- #define perSecondA 6
- // 每一分 分针 旋转
- #define perMinA 6
- // 每一小时 时针 旋转 30
- #define perHourA 30
- // 第一分钟 时针 旋转 0.5
- #define perMinHour 0.5
- // 每一秒调用一次
- - (void)timeChage{
- NSCalendar *calendar = [NSCalendar currentCalendar];
- //components 日历单元: 年, 月, 日, 时, 分, 秒
- //fromDate: 从哪个时间开始取
- NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour fromDate:[NSDate date]];
- // 获取当前时间的时 分 秒
- NSInteger curSecond = cmp.second;
- NSInteger curMinute = cmp.minute;
- NSInteger curHour = cmp.hour;
- // 秒针 旋转多少度. 当前的秒数乘以每秒转多少度.
- CGFloat angle = curSecond * perSecondA;
- self.secondL.transform = CATransform3DMakeRotation(angle2Rad(angle), 0, 0, 1);
- // 分针 旋转多少度. 当前的分钟乘以每分转多少度.
- CGFloat minuteA = curMinute * perMinA;
- self.minuteL.transform = CATransform3DMakeRotation(angle2Rad(minuteA), 0, 0, 1);
- // 时针旋转的度数应该是 多少小时对应的度数 + 分钟对应的时针旋转的度数
- CGFloat hourA = curHour * perHourA + curMinute * perMinHour;
- self.hourL.transform = CATransform3DMakeRotation(angle2Rad(hourA), 0, 0, 1);
- }
10.3 将布局和旋转进行组合
每过一秒, 我们的秒针就需要变化位置, 所以我们我们需要设置一个定时器, 在开始时每秒执行一次旋转布局绘制.
- - (void)viewDidLoad {
- [super viewDidLoad];
- // 添加时针 分针 秒针
- [self addHour];
- [self addMinue];
- [self addSecond];
- // 添加定时器, 每秒进行绘制
- [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChage) userInfo:nil repeats:YES];
- // 绘制
- [self timeChage];
- }
来源: https://www.cnblogs.com/mukekeheart/p/9371508.html