美文网首页ios动画
CALayer常用属性整理(三)

CALayer常用属性整理(三)

作者: 37b32340bcbc | 来源:发表于2016-11-11 10:35 被阅读0次

    圆角与阴影

    单纯的圆角应该没什么可说的。网上有很多设置圆角的方式。比如最简单的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,并且放上一张这样的图片。


    avatar.jpg

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


    add.png

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

    mask效果图.png

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

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

    minificationFilter和magnificationFilter

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

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

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

    这次就先坑到这。

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

    相关文章

      网友评论

        本文标题:CALayer常用属性整理(三)

        本文链接:https://www.haomeiwen.com/subject/zbvzuttx.html