其实我也不知道用什么词来形容这个效果,就是类似扣扣消息的背景,原本是一张图片,但是图片多了一个边脚。一般的人都应该见过,也不是什么很难实现的效果,这里想分享一下,希望能帮助正在爬坑的小伙伴。
这个效果是利用了UIView的layer特性,通过画出layer的路径,可以将一张图片显示成我们想要的形状。从理论上讲,可以是任意的规则或不规则图形。接下来看核心代码。
1 @interface LMFShapeImageView () 2 { 3 CALayer *_contentLayer; 4 CAShapeLayer *_maskLayer; 5 } 6 @end 7 8 @implementation LMFShapeImageView 9 10 - (instancetype)initWithFrame:(CGRect)frame and:(float)subY 11 { 12 self = [super initWithFrame:frame]; 13 if (self) { 14 self.userInteractionEnabled = YES; 15 [self setup:subY]; 16 } 17 return self; 18 } 19 - (void)setup:(float)subY 20 { 21 _maskLayer = [CAShapeLayer layer]; 22 _maskLayer.path = [self getPathWith:subY]; 23 _maskLayer.fillColor = [UIColor blackColor].CGColor; 24 _maskLayer.strokeColor = [UIColor blackColor].CGColor; 25 _maskLayer.frame = self.bounds; 26 _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1); 27 _maskLayer.contentsScale = [UIScreen mainScreen].scale; //非常关键设置自动拉伸的效果且不变形 28 _maskLayer.lineWidth = 1; 29 _contentLayer = [CALayer layer]; 30 _contentLayer.mask = _maskLayer; 31 _contentLayer.frame = self.bounds; 32 self.layer.masksToBounds = YES; 33 [self.layer addSublayer:_contentLayer]; 34 35 } 36 37 - (CGPathRef)getPathWith:(float)sub 38 { 39 float subY = sub; 40 CGFloat width = self.frame.size.width; 41 CGFloat x = 2; 42 CGFloat k = sqrt(x*width+3/4*x*x)-sqrt(3); 43 // CGFloat r = (width-sqrt(3)*k+x)/2.0-subY; 44 CGFloat r = width/2.0 - width/12.0 -subY; 45 CGPoint A = CGPointMake(width/2.0, width-subY); 46 CGPoint B = CGPointMake(width/2.0-k, 2*r-x-sqrt(2)*subY/2); 47 CGPoint C = CGPointMake(width/2.0-r, r+subY); 48 CGPoint D = CGPointMake(width/2.0, 0+subY); 49 CGPoint E = CGPointMake(width/2.0+r, r+subY); 50 CGPoint F = CGPointMake(width/2.0+k, 2*r-x-sqrt(2)*subY/2); 51 52 NSMutableArray *pointArray = [NSMutableArray array]; 53 [pointArray addObject:[NSValue valueWithCGPoint:B]]; 54 [pointArray addObject:[NSValue valueWithCGPoint:C]]; 55 [pointArray addObject:[NSValue valueWithCGPoint:D]]; 56 [pointArray addObject:[NSValue valueWithCGPoint:E]]; 57 [pointArray addObject:[NSValue valueWithCGPoint:F]]; 58 CGMutablePathRef path = CGPathCreateMutable(); 59 60 CGFloat radius = r; 61 CGPathMoveToPoint(path, NULL, width/2.0, 2*r+subY); 62 CGPathAddArcToPoint(path, NULL, C.x, 2*r+subY, C.x, C.y, radius); 63 CGPathAddArcToPoint(path, NULL, C.x, D.y, D.x, D.y, radius); 64 CGPathAddArcToPoint(path, NULL, E.x, D.y, E.x, E.y, radius); 65 CGPathAddArcToPoint(path, NULL, E.x, 2*r+subY, width/2.0, 2*r+subY, radius); 66 CGPathMoveToPoint(path, NULL, A.x, A.y); 67 CGPathAddLineToPoint(path, NULL, B.x, B.y); 68 CGPathAddLineToPoint(path, NULL, F.x, F.y); 69 CGPathAddLineToPoint(path, NULL, A.x, A.y); 70 71 // CGPathMoveToPoint(path, NULL, width/2.0, width); 72 // //->C 73 // CGPathAddArcToPoint(path, NULL, 0, width, 0, width/2.0, width/2.0); 74 // //C->D 75 // CGPathAddArcToPoint(path, NULL, 0, 0, width/2.0, 0, width/2.0); 76 // //D->E 77 // CGPathAddArcToPoint(path, NULL, width, 0, width, width/2.0, width/2.0); 78 // //E->F 79 // CGPathAddArcToPoint(path, NULL, width, width, width/2.0, width, width/2.0); 80 return path; 81 82 } 83 84 - (void)setImage:(UIImage *)image 85 { 86 _contentLayer.contents = (id)image.CGImage; 87 }
代码很少,慢慢研究其实很简单的,下面是使用,感觉还是附上比较好。
1 LMFShapeImageView *backImage = [[LMFShapeImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50) and:0.5]; 2 backImage.image = [UIImage imageNamed:@"white_image_back"];3 [self addSubview:backImage]; 4 LMFShapeImageView *userImage = [[LMFShapeImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50) and:2.5]; 5 [userImage setImageWithURL:[NSURL URLWithString:[ALUser currentUser].avatar]]; 6 [backImage addSubview:userImage];
下面是效果图