gitbook地址
CALayer的几个属性和方法
contents:
// 你给contents赋的不是CGImage,那么你得到的图层将是空白的
layer.contents = (__bridge id)image.CGImage;
contentGravity:
// UIView有一个叫做contentMode,CALayer对应的属性叫做contentGravity
contentsScale:
// 寄宿图的像素尺寸和视图大小的比例
// 如果contentsScale设置为1.0,将会以每个点1个像素绘制图片,如果设置为2.0,则会以每个点2个像素绘制图片
layer.contentsScale = [UIScreen mainScreen].scale;
maskToBounds:
// UIView有一个叫做clipsToBounds,CALayer对应的属性叫做masksToBounds
contentsRect:
// contentsRect是{0, 0, 1, 1},按比例
// contentsRect{0,0,0.5,0.5} 则是左上角四分之一的图
contentsCenter:
// contentsCenter其实是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域
// 气泡拉伸,android的.9图片
Custom Drawing
- 通过继承UIView并实现-drawRect:方法来自定义绘制
- 实现CALayerDelegate:
/**
* 1.设置delegate
* 2. 调用display
* 3. 实现drawLayer:方法,方法内绘图
*/
CALayer *blueLayer = [CALayer layer];
blueLayer.delegate = self;
[blueLayer display];
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
//draw a thick red circle
CGContextSetLineWidth(ctx, 10.0f);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextStrokeEllipseInRect(ctx, layer.bounds);
}
总结:
CALayerDelegate绘制:寄宿图不会自动重绘它的内容,决定权交给了开发者,通过调用display。
UIView的-drawRect绘制:UIView会帮你做完剩下的工作,无需手动调用display。
图层几何学
布局:
frame:代表了图层的外部坐标(也就是在父图层上占据的空间)
bounds:是内部坐标({0, 0}通常是图层的左上角)
center和position:都代表了相对于父图层anchorPoint所在的位置
注意:frame并不是一个非常清晰的属性,它其实是一个虚拟属性,是根据bounds,position和transform计算而来,改变frame的值同样会影响到他们当中的值
注意:当对图层做变换的时候,比如旋转或者缩放,frame实际上代表了覆盖在图层旋转之后的整个轴对齐的矩形区域,也就是说frame的宽高可能和bounds的宽高不再一致了,如图
锚点(anchorPoint)(注意:center和position都代表了相对于父图层anchorPoint所在的位置)
默认位置:anchorPoint位于图层的中点
大小范围:{0,0}->{1,1} (contentsRect和contentsCenter属性类似)
锚点的作用:eg 实现一个
@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIImageView *hourHand;
@property (nonatomic, weak) IBOutlet UIImageView *minuteHand;
@property (nonatomic, weak) IBOutlet UIImageView *secondHand;
@property (nonatomic, weak) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//start timer
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tick) userInfo:nil repeats:YES];
//set initial hand positions
[self tick];
}
- (void)tick
{
//convert time to hours, minutes and seconds
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;
//calculate hour hand angle //calculate minute hand angle
CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;
//calculate second hand angle
CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0;
//rotate hands
self.hourHand.transform = CGAffineTransformMakeRotation(hoursAngle);
self.minuteHand.transform = CGAffineTransformMakeRotation(minsAngle);
self.secondHand.transform = CGAffineTransformMakeRotation(secsAngle);
}
@end
效果图:
改变锚点之后:
- (void)viewDidLoad
{
[super viewDidLoad];
// adjust anchor points
self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
}
效果图:
坐标系
z坐标轴
zPosition:控制视图层级,越大的处于视图越上面,上面的视图会遮挡下面的视图(可以改变屏幕上图层的顺序,但不能改变事件传递的顺序)
anchorPointZ:z方向锚点
layer的方法:
containsPoint:接受一个在本图层坐标系下的CGPoint,如果这个点在图层frame范围内就返回YES
hitTest:返回图层本身,或者包含这个坐标点的叶子节点图层(测算的顺序严格依赖于图层树当中的图层顺序)
视觉效果
conrnerRadius: 圆角角度
masksToBounds: 裁剪
borderWidth:边框宽度
borderColor:边框颜色
shadowColor:阴影颜色
shadowOffset:阴影的方向和距离
shadowRadius:阴影模糊度
shadowPath:阴影的样式
// shadowPath使用:
//create a square shadow
CGMutablePathRef squarePath = CGPathCreateMutable();
CGPathAddRect(squarePath, NULL, self.layerView1.bounds);
self.layerView1.layer.shadowPath = squarePath; CGPathRelease(squarePath);
//create a circular shadow
CGMutablePathRef circlePath = CGPathCreateMutable();
CGPathAddEllipseInRect(circlePath, NULL, self.layerView2.bounds);
self.layerView2.layer.shadowPath = circlePath; CGPathRelease(circlePath);
// 如果是一个矩形或者是圆,用CGPath会相当简单明了。但是如果是更加复杂一点的图形,UIBezierPath类会更合适
阴影的裁剪:(用一个额外的视图来解决阴影裁切的问题)
内层:设置masksToBounds = yes
外层:设置masksToBounds = no and shadow。
CALayer属性mask,蒙板原理实现不规则裁剪
//create mask layer
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = self.layerView.bounds;
UIImage *maskImage = [UIImage imageNamed:@"Cone.png"];
maskLayer.contents = (__bridge id)maskImage.CGImage;
//apply mask to image layer
self.imageView.layer.mask = maskLayer;
CALayer蒙板图层真正厉害的地方在于蒙板图不局限于静态图。任何有图层构成的都可以作为mask属性,这意味着你的蒙板可以通过代码甚至是动画实时生成。
layer拉伸与裁剪
layer.magnificationFilter
// 图片拉伸算法
kCAFilterLinear
kCAFilterNearest
kCAFilterTrilinear
//set up digit views
for (UIView *view in self.digitViews) {
//set contents
view.layer.contents = (__bridge id)digits.CGImage;
view.layer.contentsRect = CGRectMake(0, 0, 0.1, 1.0);
view.layer.contentsGravity = kCAGravityResizeAspect;
}
组透明
CALayer属性:opacity(等同UIView的alpha的属性来确定视图的透明度。)
CALayer属性:shouldRasterize(来实现组透明的效果,如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,然后再透明)
//enable rasterization for the translucent button
button2.layer.shouldRasterize = YES;
button2.layer.rasterizationScale = [UIScreen mainScreen].scale;
// 设置rasterizationScale属性去匹配屏幕,以防止出现Retina屏幕像素化的问题
变换
专用图层
CAShapeLayer: