iOS 不规则的ImageView

http://blog.csdn.net/johnzhjfly/article/details/41175015?utm_source=tuicool&utm_medium=referral


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


那如何去实现?

通常图片都是矩形的,如果想在客户端去实现不规则的头像,需要自己去实现。

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

2.使用CAShapeLayer, CALayer如何去实现

我们来看看如何使用CAShapeLayer去实现,

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

  1. #import "ShapedImageView.h"  
  2.   
  3. @interface ShapedImageView()  
  4. {  
  5.     CALayer      *_contentLayer;  
  6.     CAShapeLayer *_maskLayer;  
  7. }  
  8. @end  
  9.   
  10. @implementation ShapedImageView  
  11.   
  12. - (instancetype)initWithFrame:(CGRect)frame  
  13. {  
  14.     self = [super initWithFrame:frame];  
  15.     if (self) {  
  16.         [self setup];  
  17.     }  
  18.     return self;  
  19. }  
  20.   
  21. - (void)setup  
  22. {  
  23.     _maskLayer = [CAShapeLayer layer];  
  24.     _maskLayer.path = [UIBezierPath bezierPathWithOvalInRect:self.bounds].CGPath;  
  25.     _maskLayer.fillColor = [UIColor blackColor].CGColor;  
  26.     _maskLayer.strokeColor = [UIColor redColor].CGColor;  
  27.     _maskLayer.frame = self.bounds;  
  28.     _maskLayer.contentsCenter = CGRectMake(0.50.50.10.1);  
  29.     _maskLayer.contentsScale = [UIScreen mainScreen].scale;  
  30.       
  31.     _contentLayer = [CALayer layer];  
  32.     _contentLayer.mask = _maskLayer;  
  33.     _contentLayer.frame = self.bounds;  
  34.     [self.layer addSublayer:_contentLayer];  
  35.       
  36. }  
  37.   
  38. - (void)setImage:(UIImage *)image  
  39. {  
  40.     _contentLayer.contents = (id)image.CGImage;  
  41. }  
  42.   
  43. @end  
声明了用于maskLayer个CAShapedLayer, CAShapedLayer有个path的属性,将内容Layer的mask设置为maskLayer, 就可以获取到我们想要的形状。

path我们可以使用CAMutablePath任意的构造,上述的代码运行想过如下:


如果将代码改成

  1. _maskLayer = [CAShapeLayer layer];  
  2. _maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:20].CGPath;  
  3. _maskLayer.fillColor = [UIColor blackColor].CGColor;  
  4. _maskLayer.strokeColor = [UIColor redColor].CGColor;  
  5. _maskLayer.frame = self.bounds;  
  6. _maskLayer.contentsCenter = CGRectMake(0.50.50.10.1);  
  7. _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //非常关键设置自动拉伸的效果且不变形  
  8.   
  9. _contentLayer = [CALayer layer];  
  10. _contentLayer.mask = _maskLayer;  
  11. _contentLayer.frame = self.bounds;  
  12. [self.layer addSublayer:_contentLayer];  
的效果:

如果将代码改成:

  1. CGMutablePathRef path = CGPathCreateMutable();  
  2. CGPoint origin = self.bounds.origin;  
  3. CGFloat radius = CGRectGetWidth(self.bounds) / 2;  
  4. CGPathMoveToPoint(path, NULL, origin.x, origin.y + 22 *radius);  
  5. CGPathMoveToPoint(path, NULL, origin.x, origin.y + radius);  
  6.   
  7. CGPathAddArcToPoint(path, NULL, origin.x, origin.y, origin.x + radius, origin.y, radius);  
  8. CGPathAddArcToPoint(path, NULL, origin.x + 22 * radius, origin.y, origin.x + 22 * radius, origin.y + radius, radius);  
  9. CGPathAddArcToPoint(path, NULL, origin.x + 22 * radius, origin.y + 22 * radius, origin.x + radius, origin.y + 2  * radius, radius);  
  10. CGPathAddLineToPoint(path, NULL, origin.x, origin.y + 22 * radius);  
  11.   
  12. _maskLayer = [CAShapeLayer layer];  
  13. _maskLayer.path = path;  
  14. _maskLayer.fillColor = [UIColor blackColor].CGColor;  
  15. _maskLayer.strokeColor = [UIColor clearColor].CGColor;  
  16. _maskLayer.frame = self.bounds;  
  17. _maskLayer.contentsCenter = CGRectMake(0.50.50.10.1);  
  18. _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //非常关键设置自动拉伸的效果且不变形  
  19.   
  20. _contentLayer = [CALayer layer];  
  21. _contentLayer.mask = _maskLayer;  
  22. _contentLayer.frame = self.bounds;  
  23. [self.layer addSublayer:_contentLayer];  
将是这个效果:


理论上我们可以构造出任意想要的形状,但是有些形状如果你不熟悉几何知识的话是构造不出正确的

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

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

  1. _maskLayer = [CAShapeLayer layer];  
  2. _maskLayer.fillColor = [UIColor blackColor].CGColor;  
  3. _maskLayer.strokeColor = [UIColor clearColor].CGColor;  
  4. _maskLayer.frame = self.bounds;  
  5. _maskLayer.contentsCenter = CGRectMake(0.50.50.10.1);  
  6. _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //非常关键设置自动拉伸的效果且不变形  
  7. _maskLayer.contents = (id)[UIImage imageNamed:@"gray_bubble_right@2x.png"].CGImage;  
  8.   
  9. _contentLayer = [CALayer layer];  
  10. _contentLayer.mask = _maskLayer;  
  11. _contentLayer.frame = self.bounds;  
  12. [self.layer addSublayer:_contentLayer];  

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

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

此时理想的解决方案是使用CGPath或者UIBezierPath构建不规则的path,然后clip画出来,这里就不详细讲解了。示例代码如下:

  1. - (UIImage *)maskImage  
  2. {  
  3.     // start with an image  
  4.     UIImage * fooImage = self;//[UIImage imageNamed:@"foo.png"];  
  5.     CGRect imageRect = CGRectMake(00, fooImage.size.width, fooImage.size.height);  
  6.     // set the implicit graphics context ("canvas") to a bitmap context for images  
  7.     UIGraphicsBeginImageContextWithOptions(imageRect.sizeNO0.0);  
  8.     // create a bezier path defining rounded corners  
  9.     UIBezierPath * path = [UIBezierPath bezierPathWithRect:imageRect];  
  10.     CGFloat radius = fooImage.size.width / 2.5;  
  11.     CGFloat _radius = radius;  
  12.     //construct your shaped path  
  13.     [path moveToPoint:CGPointMake(00)];  
  14.     [path addArcWithCenter:CGPointMake(radius, radius) radius:_radius startAngle:M_PI endAngle:33 * M_PI / 2 clockwise:TRUE];  
  15.     [path moveToPoint:CGPointMake(fooImage.size.width0)];  
  16.     [path addArcWithCenter:CGPointMake(fooImage.size.width - radius, radius) radius:_radius startAngle:33 * M_PI / 2 endAngle:22 * M_PI clockwise:TRUE];  
  17.     [path moveToPoint:CGPointMake(fooImage.size.width, fooImage.size.height)];  
  18.     [path addArcWithCenter:CGPointMake(fooImage.size.width - radius, fooImage.size.height - radius) radius:_radius startAngle:0 endAngle:M_PI / 2 clockwise:TRUE];  
  19.     [path moveToPoint:CGPointMake(0, fooImage.size.height)];  
  20.     [path addArcWithCenter:CGPointMake(radius, fooImage.size.height - radius) radius:_radius startAngle:M_PI / 2 endAngle:M_PI clockwise:TRUE];  
  21.     path.flatness = 1000;  
  22.     path.lineCapStyle = kCGLineCapRound;  
  23.     path.lineJoinStyle = kCGLineJoinRound;  
  24.     // use this path for clipping in the implicit context  
  25.     [path addClip];  
  26.     // draw the image into the implicit context  
  27.     [fooImage drawInRect:imageRect];  
  28.     // save the clipped image from the implicit context into an image  
  29.     UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();  
  30.     // cleanup  
  31.     UIGraphicsEndImageContext();  
  32.     return maskedImage; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值