首页 > 系统 > iOS > 正文

iOS 不规则的ImageView

2019-11-09 16:47:17
字体:
来源:转载
供稿:网友

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, 代码如下:

[objc] view plain copy 在CODE上查看代码片#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,%20CAShapedLayer有个path的属性,将内容Layer的mask设置为maskLayer,%20就可以获取到我们想要的形状。

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

如果将代码改成

[objc] view plain copy 在CODE上查看代码片_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];  的效果:

如果将代码改成:

[objc] view plain copy 在CODE上查看代码片CGMutablePathRef path = CGPathCreateMutable();  CGPoint origin = self.bounds.origin;  CGFloat radius = CGRectGetWidth(self.bounds) / 2;  CGPathMoveToPoint(path, NULL, origin.x, origin.y + 22 *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 + 22 * radius, origin.y, origin.x + 22 * radius, origin.y + radius, radius);  CGPathAddArcToPoint(path, NULL, origin.x + 22 * radius, origin.y + 22 * radius, origin.x + radius, origin.y + 2  * radius, radius);  CGPathAddLineToPoint(path, NULL, origin.x, origin.y + 22 * 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呢?答案是肯定的,代码如下:

[objc] view plain copy 在CODE上查看代码片_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画出来,这里就不详细讲解了。示例代码如下:

[objc] view plain copy 在CODE上查看代码片- (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:33 * M_PI / 2 clockwise:TRUE];      [path moveToPoint:CGPointMake(fooImage.size.width, 0)];      [path addArcWithCenter:CGPointMake(fooImage.size.width - radius, radius) radius:_radius startAngle:33 * M_PI / 2 endAngle:22 * 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; 
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表