CALayer我们又称它叫做层。在每个UIView内部都有一个layer这样一个属性,UIView之所以能够显示,就是因为它里面有这个layer才具有显示的功能。我们可以通过操作CALayer对象,可以很方便地调整UIView的一些外观属性,可以给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;
//设置图形边框
_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,把就会把超过根层以外的东西都给裁剪掉。
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"];
自定义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];
为了保证可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef
在明白要怎么选择之前,我们先了解一下UIView和layer的不同点:
drawRect
方法,将要绘制的东西绘制到图层上,然后拷贝图层,完成了UIView的显示所以,对比CALayer,UIView多了一个事件处理的功能。也就是说,CALayer不能处理用户的触摸事件,而UIView可以。
如果显示出来的东西需要跟用户进行交互的话,用UIView;
如果不需要跟用户进行交互,用UIView或者CALayer都可以,CALayer的性能会高一些,因为它少了事件处理的功能,更加轻量级。
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);
了解什么是隐式动画,要先了解是什么根层和非根层:
隐式动画就是当对非根层的部分属性进行修改时, 它会自动的产生一些动画的效果,我们称这个默认产生的动画为隐式动画.
首先要了解动画底层是怎么做的,动画的底层是包装成一个事务来进行的。
什么是事务? 很多操作绑定在一起,当这些操作执行完毕后,才去执行下一个操作.
//开启事务
[CATransaction begin];
//设置事务没有动画
[CATransaction setDisableActions:YES];
//设置动画执行的时长
[CATransaction setAnimationDuration:2];
//提交事务
[CATransaction commit];
界面上时针、分针、秒针不需要与用户进行交互,所以都可以使用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];
}
//时针、分针的添加方式类似,只是设置的宽高有点区别,不再贴出来
//角度转换成弧度
#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);
}
每过一秒,我们的秒针就需要变化位置,所以我们我们需要设置一个定时器,在开始时每秒执行一次旋转布局绘制。
- (void)viewDidLoad {
[super viewDidLoad];
//添加时针 分针 秒针
[self addHour];
[self addMinue];
[self addSecond];
//添加定时器,每秒进行绘制
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChage) userInfo:nil repeats:YES];
//绘制
[self timeChage];
}