我们在做iOS开发的时候,往往需要实现不规则形状的头像,如:
那如何去实现?
通常图片都是矩形的,如果想在客户端去实现不规则的头像,需要自己去实现。
1.使用layer去实现, 见http://blog.csdn.net/johnzhjfly/article/details/39993345
2.使用CAShapeLayer, CALayer如何去实现
我们来看看如何使用CAShapeLayer去实现,
定义一个ShapedImageView,继承于UIView, 代码如下:
[objc]view plaincopy
#import "ShapedImageView.h"
@interfaceShapedImageView()
{
CALayer *_contentLayer;
CAShapeLayer*_maskLayer;
}
@end
@implementationShapedImageView
- (instancetype)initWithFrame:(CGRect)frame
{
self= [superinitWithFrame:frame];
if(self) {
[selfsetup];
}
returnself;
}
- (void)setup
{
_maskLayer = [CAShapeLayerlayer];
_maskLayer.path= [UIBezierPathbezierPathWithOvalInRect:self.bounds].CGPath;
_maskLayer.fillColor= [UIColorblackColor].CGColor;
_maskLayer.strokeColor= [UIColorredColor].CGColor;
_maskLayer.frame=self.bounds;
_maskLayer.contentsCenter= CGRectMake(0.5,0.5,0.1,0.1);
_maskLayer.contentsScale= [UIScreenmainScreen].scale;
_contentLayer = [CALayerlayer];
_contentLayer.mask= _maskLayer;
_contentLayer.frame=self.bounds;
[self.layeraddSublayer:_contentLayer];
}
- (void)setImage:(UIImage*)image
{
_contentLayer.contents= (id)image.CGImage;
}
@end
声明了用于maskLayer个CAShapedLayer, CAShapedLayer有个path的属性,将内容Layer的mask设置为maskLayer, 就可以获取到我们想要的形状。
path我们可以使用CAMutablePath任意的构造,上述的代码运行想过如下:
如果将代码改成
[objc]view plaincopy
_maskLayer = [CAShapeLayerlayer];
_maskLayer.path= [UIBezierPathbezierPathWithRoundedRect:self.boundscornerRadius:20].CGPath;
_maskLayer.fillColor= [UIColorblackColor].CGColor;
_maskLayer.strokeColor= [UIColorredColor].CGColor;
_maskLayer.frame=self.bounds;
_maskLayer.contentsCenter= CGRectMake(0.5,0.5,0.1,0.1);
_maskLayer.contentsScale= [UIScreenmainScreen].scale;//非常关键设置自动拉伸的效果且不变形
_contentLayer = [CALayerlayer];
_contentLayer.mask= _maskLayer;
_contentLayer.frame=self.bounds;
[self.layeraddSublayer:_contentLayer];
的效果:
如果将代码改成:
[objc]view plaincopy
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 = [CAShapeLayerlayer];
_maskLayer.path= path;
_maskLayer.fillColor= [UIColorblackColor].CGColor;
_maskLayer.strokeColor= [UIColorclearColor].CGColor;
_maskLayer.frame=self.bounds;
_maskLayer.contentsCenter= CGRectMake(0.5,0.5,0.1,0.1);
_maskLayer.contentsScale= [UIScreenmainScreen].scale;//非常关键设置自动拉伸的效果且不变形
_contentLayer = [CALayerlayer];
_contentLayer.mask= _maskLayer;
_contentLayer.frame=self.bounds;
[self.layeraddSublayer:_contentLayer];
将是这个效果:
理论上我们可以构造出任意想要的形状,但是有些形状如果你不熟悉几何知识的话是构造不出正确的
path的,从代码上我们可以看到我们可以通过设置CALayer的contents属性来设置显示的内容,那我们
是不是可以通过设置CAShapedLayer的contents来设置maskLayer呢?答案是肯定的,代码如下:
[objc]view plaincopy
_maskLayer = [CAShapeLayerlayer];
_maskLayer.fillColor= [UIColorblackColor].CGColor;
_maskLayer.strokeColor= [UIColorclearColor].CGColor;
_maskLayer.frame=self.bounds;
_maskLayer.contentsCenter= CGRectMake(0.5,0.5,0.1,0.1);
_maskLayer.contentsScale= [UIScreenmainScreen].scale;//非常关键设置自动拉伸的效果且不变形
_maskLayer.contents= (id)[UIImageimageNamed:@"gray_bubble_right@2x.png"].CGImage;
_contentLayer = [CALayerlayer];
_contentLayer.mask= _maskLayer;
_contentLayer.frame=self.bounds;
[self.layeraddSublayer:_contentLayer];
gray_bubble_right就是你想要的形状,运行效果如下:
不停的改变CALayer的一个坏处就是非常的损耗性能,如果你有一个cell的列表,每个列表有个头像的话,快速滑动的时候,你会发现非常的卡。
此时理想的解决方案是使用CGPath或者UIBezierPath构建不规则的path,然后clip画出来,这里就不详细讲解了。示例代码如下:
[objc]view plaincopy
- (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 = [UIBezierPathbezierPathWithRect:imageRect];
CGFloat radius = fooImage.size.width/2.5;
CGFloat _radius = radius;
//construct your shaped path
[pathmoveToPoint:CGPointMake(0,0)];
[pathaddArcWithCenter:CGPointMake(radius, radius)radius:_radiusstartAngle:M_PIendAngle:33* M_PI /2clockwise:TRUE];
[pathmoveToPoint:CGPointMake(fooImage.size.width,0)];
[pathaddArcWithCenter:CGPointMake(fooImage.size.width- radius, radius)radius:_radiusstartAngle:33* M_PI /2endAngle:22* M_PIclockwise:TRUE];
[pathmoveToPoint:CGPointMake(fooImage.size.width, fooImage.size.height)];
[pathaddArcWithCenter:CGPointMake(fooImage.size.width- radius, fooImage.size.height- radius)radius:_radiusstartAngle:0endAngle:M_PI /2clockwise:TRUE];
[pathmoveToPoint:CGPointMake(0, fooImage.size.height)];
[pathaddArcWithCenter:CGPointMake(radius, fooImage.size.height- radius)radius:_radiusstartAngle:M_PI /2endAngle:M_PIclockwise:TRUE];
path.flatness=1000;
path.lineCapStyle= kCGLineCapRound;
path.lineJoinStyle= kCGLineJoinRound;
// use this path for clipping in the implicit context
[pathaddClip];
// draw the image into the implicit context
[fooImagedrawInRect:imageRect];
// save the clipped image from the implicit context into an image
UIImage*maskedImage = UIGraphicsGetImageFromCurrentImageContext();
// cleanup
UIGraphicsEndImageContext();
returnmaskedImage;
}
转载 -- http://blog.csdn.net/johnzhjfly/article/details/41175015