CALayer常用属性整理(三)

圆角与阴影

单纯的圆角应该没什么可说的。网上有很多设置圆角的方式。比如最简单的layer.cornerRadius,图层蒙版或者CAShapeLayer。

在使用cornerRadius属性时,他只会作用于前景框和背景色,对于contents有内容的图层或者内部还有子视图的控件(比如UILabel)只单一的设置这个属性是不会显示出圆角效果的。多数情况下我们会这样写

layer.cornerRadius = 5;
layer.masksToBounds = YES;

这样做很显然会导致离屏渲染,当然圆角数量不多的情况下根本不需要在乎这个问题。但是在滚动视图比如table或者collection上如果也需要使用cornerRadius和masksToBounds的话就需要再加上两句话来挽救我们的帧数。

layer.shouldRasterize = YES;
layer.rasterizationScale = [UIScreen mainScreen].scale;

上面两行代码会将把视图内的内容进行缓存。这样做的弊端也很明显,一旦视图的内容被改变缓存就失去意义了。

还有一些为视图添加圆角的方法。这里举出一个为图片添加圆角的例子(原文)
- (UIImage*)imageAddCornerWithRadius:(CGFloat)radius andSize:(CGSize)size{
CGRect rect = CGRectMake(0, 0, size.width, size.height);

  UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen   mainScreen].scale);
  CGContextRef ctx = UIGraphicsGetCurrentContext();
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radius, radius)];
  CGContextAddPath(ctx,path.CGPath);
  CGContextClip(ctx);
  [self drawInRect:rect];
  CGContextDrawPath(ctx, kCGPathFillStroke);
  UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return newImage;
}

原谅我把代码厚颜无耻的直接复制过来了(hiahia),使用时把这个方法加在UIImage的extends里面然后这样调用就可以了。

UIImageView *imageView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"avatar.jpg"] imageAddCornerWithRadius:15 andSize:CGSizeMake(200, 200)]];

CALayer有五个关于阴影的属性,将图层的shadowOpacity属性设置为一个大于0小于1的值时将会在图层下出现阴影。shadowColor设置阴影颜色。

shadowOffset是一个CGSize值,默认是(0,-3)。就是阴影会出现在图层上方。至于为什么会是上方,还是和Mac OS有关,因为Mac OS和iOS的Y轴是相反的。shadowRadius负责调整阴影的模糊度,默认是3.0,数值越大越模糊。shadowPath用来指定一个阴影的绘制形状。此外shadowPath的另外一个用处是解决离屏渲染的问题,设置图层阴影会导致离屏渲染的发生,过多的阴影会影响到性能甚至用户体验。我们可以在设置阴影的代码后面加上这样一句

layer.shadowPath = [UIBezierPath bezierPathWithRect:layer.bounds].CGPath;

通过手动指定阴影路径,从而避免Core Animation自动计算引起的离屏渲染。

关于圆角和阴影还有一个很古老的问题,就是给一个圆角视图添加阴影。关于这个问题的出现还是说一下吧,万一有萌新不知道呢- -、。

当我们使用cornerRadius给视图添加圆角时,很多时候因为contents里面有内容,所以不得不使用masksToBounds来将多余的部分裁剪掉。如果这个时候这个视图被设置了阴影属性,那么阴影也将会被视为多余的部分被一起裁剪。这踏马就很尴尬了,要阴影就不能设置masksToBounds,不设置masksToBounds就没有圆角。

这个问题有不止一个解决办法。最直观的办法就是把原来的一层layer换成两层,一层负责阴影和圆角,另一层负责显示内容,这样就不会再有冲突。

    UIView *shadowView = [[UIView alloc] initWithFrame:CGRectMake(10, 250, 150, 150)];
  shadowView.layer.shadowOpacity = 0.5;
  shadowView.layer.cornerRadius = 15;
  shadowView.layer.shadowOffset = CGSizeMake(15, 15);
  shadowView.backgroundColor = [UIColor whiteColor];
  [self.view addSubview:shadowView];

  CALayer *shadowLayer = [CALayer layer];
  shadowLayer.frame = shadowView.bounds;
  shadowLayer.cornerRadius = 15;
  shadowLayer.masksToBounds = YES;
  shadowLayer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"avatar.jpg"].CGImage);
  [shadowView.layer addSublayer:shadowLayer];

首先创建一个View,在View自带的layer上添加阴影属性和设置圆角(在上面提到过,单纯的设置在只有背景色或者前景框的情况下设置圆角是不需要masksToBounds配合的,因为contents里面并没有内容)。这时contents属性为nil,所以圆角和阴影是可以并存的。然后我们再创建一个新的图层(CALayer),在这层上加入图片并且设置圆角。这样就达到了圆角加阴影的效果。

文章开始就提到过使用cornerRadius+ masksToBounds的方式会引起离屏渲染,所以我们可以利用下上面我从大神那没脸没皮直接抄过来的代码。把shadowLayer改写如下:

CALayer *shadowLayer = [CALayer layer];
shadowLayer.frame = shadowView.bounds;
shadowLayer.contents = (__bridge id _Nullable)([[UIImage imageNamed:@"avatar.jpg"] imageAddCornerWithRadius:15 andSize:shadowLayer.bounds.size].CGImage);
[shadowView.layer addSublayer:shadowLayer];

图层蒙版(mask)

关于mask的解释直接看演示效果会更直观。

UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(10, 250, 150, 150)];
image.image = [UIImage imageNamed:@"avatar.jpg"];
[self.view addSubview:image];

CALayer *maskLayer = [CALayer layer];
maskLayer.frame = image.bounds;
maskLayer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"add"].CGImage);
image.layer.mask = maskLayer;

首先创建了一个ImageView,并且放上一张这样的图片。


CALayer常用属性整理(三)_第1张图片
avatar.jpg

然后创建一个图层,在图层上放一张这样的图片(项目里拖出来的,凑合用)。


add.png

都添加好后在代码最后一句将放有加号的layer作为mask属性赋给imageView。
这时就会看到这样的效果。

CALayer常用属性整理(三)_第2张图片
mask效果图.png

这样应该就很好理解了,mask被设置后就只负责渲染maskLayer内的内容,其余的部分一概不管。

另外使用mask也可以用来设置圆角,但是这样同样会产生离屏渲染的问题。很多博客都已经提到这个问题了,所以尽量不要这么做(读一声)。

minificationFilter和magnificationFilter

这两个属性决定了缩小和放大图片时的过滤器种类,有三个值可以选。

kCAFilterNearest//最近过滤算法
kCAFilterLinear//双线性滤波算法
kCAFilterTrilinear//三线性滤波算法

两个属性默认情况下是kCAFilterLinear,kCAFilterLinear和kCAFilterTrilinear在多数情况下显示效果没什么区别,kCAFilterNearest更适合于像素风格明显的图片使用。

这次就先坑到这。

参考文章:
iOS 高效添加圆角效果实战讲解
UIKit性能调优实战讲解
小心别让圆角成了你列表的帧数杀手

你可能感兴趣的:(CALayer常用属性整理(三))