zoukankan      html  css  js  c++  java
  • iOS 不规则的ImageView

    我们在做iOS开发的时候,往往须要实现不规则形状的头像,如:


    那怎样去实现?

    通常图片都是矩形的,假设想在client去实现不规则的头像,须要自己去实现。

    1.使用layer去实现, 见http://blog.csdn.net/johnzhjfly/article/details/39993345

    2.使用CAShapeLayer, CALayer怎样去实现

    我们来看看怎样使用CAShapeLayer去实现,

    定义一个ShapedImageView。继承于UIView, 代码例如以下:

    #import "ShapedImageView.h"
    
    @interface ShapedImageView()
    {
        CALayer      *_contentLayer;
        CAShapeLayer *_maskLayer;
    }
    @end
    
    @implementation ShapedImageView
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    
    - (void)setup
    {
        _maskLayer = [CAShapeLayer layer];
        _maskLayer.path = [UIBezierPath bezierPathWithOvalInRect:self.bounds].CGPath;
        _maskLayer.fillColor = [UIColor blackColor].CGColor;
        _maskLayer.strokeColor = [UIColor redColor].CGColor;
        _maskLayer.frame = self.bounds;
        _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
        _maskLayer.contentsScale = [UIScreen mainScreen].scale;
        
        _contentLayer = [CALayer layer];
        _contentLayer.mask = _maskLayer;
        _contentLayer.frame = self.bounds;
        [self.layer addSublayer:_contentLayer];
        
    }
    
    - (void)setImage:(UIImage *)image
    {
        _contentLayer.contents = (id)image.CGImage;
    }
    
    @end
    
    声明了用于maskLayer个CAShapedLayer。 CAShapedLayer有个path的属性。将内容Layer的mask设置为maskLayer, 就能够获取到我们想要的形状。

    path我们能够使用CAMutablePath随意的构造,上述的代码执行想过例如以下:


    假设将代码改成

        _maskLayer = [CAShapeLayer layer];
        _maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:20].CGPath;
        _maskLayer.fillColor = [UIColor blackColor].CGColor;
        _maskLayer.strokeColor = [UIColor redColor].CGColor;
        _maskLayer.frame = self.bounds;
        _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
        _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //很关键设置自己主动拉伸的效果且不变形
        
        _contentLayer = [CALayer layer];
        _contentLayer.mask = _maskLayer;
        _contentLayer.frame = self.bounds;
        [self.layer addSublayer:_contentLayer];
    的效果:

    假设将代码改成:

        CGMutablePathRef path = CGPathCreateMutable();
        CGPoint origin = self.bounds.origin;
        CGFloat radius = CGRectGetWidth(self.bounds) / 2;
        CGPathMoveToPoint(path, NULL, origin.x, origin.y + 2 *radius);
        CGPathMoveToPoint(path, NULL, origin.x, origin.y + radius);
        
        CGPathAddArcToPoint(path, NULL, origin.x, origin.y, origin.x + radius, origin.y, radius);
        CGPathAddArcToPoint(path, NULL, origin.x + 2 * radius, origin.y, origin.x + 2 * radius, origin.y + radius, radius);
        CGPathAddArcToPoint(path, NULL, origin.x + 2 * radius, origin.y + 2 * radius, origin.x + radius, origin.y + 2  * radius, radius);
        CGPathAddLineToPoint(path, NULL, origin.x, origin.y + 2 * radius);
        
        _maskLayer = [CAShapeLayer layer];
        _maskLayer.path = path;
        _maskLayer.fillColor = [UIColor blackColor].CGColor;
        _maskLayer.strokeColor = [UIColor clearColor].CGColor;
        _maskLayer.frame = self.bounds;
        _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
        _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //很关键设置自己主动拉伸的效果且不变形
        
        _contentLayer = [CALayer layer];
        _contentLayer.mask = _maskLayer;
        _contentLayer.frame = self.bounds;
        [self.layer addSublayer:_contentLayer];
    将是这个效果:


    理论上我们能够构造出随意想要的形状。可是有些形状假设你不熟悉几何知识的话是构造不出正确的

    path的,从代码上我们能够看到我们能够通过设置CALayer的contents属性来设置显示的内容,那我们

    是不是能够通过设置CAShapedLayer的contents来设置maskLayer呢?答案是肯定的,代码例如以下:

        _maskLayer = [CAShapeLayer layer];
        _maskLayer.fillColor = [UIColor blackColor].CGColor;
        _maskLayer.strokeColor = [UIColor clearColor].CGColor;
        _maskLayer.frame = self.bounds;
        _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
        _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //很关键设置自己主动拉伸的效果且不变形
        _maskLayer.contents = (id)[UIImage imageNamed:@"gray_bubble_right@2x.png"].CGImage;
        
        _contentLayer = [CALayer layer];
        _contentLayer.mask = _maskLayer;
        _contentLayer.frame = self.bounds;
        [self.layer addSublayer:_contentLayer];
    
    

    gray_bubble_right就是你想要的形状,执行效果例如以下:

    不停的改变CALayer的一个坏处就是很的损耗性能,假设你有一个cell的列表。每一个列表有个头像的话。高速滑动的时候。你会发现很的卡。

    此时理想的解决方式是使用CGPath或者UIBezierPath构建不规则的path,然后clip画出来。这里就不具体解说了。

    演示样例代码例如以下:

    - (UIImage *)maskImage
    {
        // start with an image
        UIImage * fooImage = self;//[UIImage imageNamed:@"foo.png"];
        CGRect imageRect = CGRectMake(0, 0, fooImage.size.width, fooImage.size.height);
        // set the implicit graphics context ("canvas") to a bitmap context for images
        UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, 0.0);
        // create a bezier path defining rounded corners
        UIBezierPath * path = [UIBezierPath bezierPathWithRect:imageRect];
        CGFloat radius = fooImage.size.width / 2.5;
        CGFloat _radius = radius;
        //construct your shaped path
        [path moveToPoint:CGPointMake(0, 0)];
        [path addArcWithCenter:CGPointMake(radius, radius) radius:_radius startAngle:M_PI endAngle:3 * M_PI / 2 clockwise:TRUE];
        [path moveToPoint:CGPointMake(fooImage.size.width, 0)];
        [path addArcWithCenter:CGPointMake(fooImage.size.width - radius, radius) radius:_radius startAngle:3 * M_PI / 2 endAngle:2 * M_PI clockwise:TRUE];
        [path moveToPoint:CGPointMake(fooImage.size.width, fooImage.size.height)];
        [path addArcWithCenter:CGPointMake(fooImage.size.width - radius, fooImage.size.height - radius) radius:_radius startAngle:0 endAngle:M_PI / 2 clockwise:TRUE];
        [path moveToPoint:CGPointMake(0, fooImage.size.height)];
        [path addArcWithCenter:CGPointMake(radius, fooImage.size.height - radius) radius:_radius startAngle:M_PI / 2 endAngle:M_PI clockwise:TRUE];
        path.flatness = 1000;
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinRound;
        // use this path for clipping in the implicit context
        [path addClip];
        // draw the image into the implicit context
        [fooImage drawInRect:imageRect];
        // save the clipped image from the implicit context into an image
        UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
        // cleanup
        UIGraphicsEndImageContext();
        return maskedImage;
    }

    源码

  • 相关阅读:
    文件读取
    命名实体识别训练集汇总(一直更新)
    基于PyTorch的Seq2Seq翻译模型详细注释介绍(一)
    python if elif else 区别
    乱码
    dataframe添加元素指定为列表,不同for循环命名空间下的变量重复问题
    tensorflow兼容处理 tensorflow.compat.v1
    Kerberos
    Hadoop集群datanode磁盘不均衡的解决方案
    Saltstack
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5244758.html
Copyright © 2011-2022 走看看