摘要
本文旨在记录使用贝塞尔曲线实现一个小需求的完整过程。使用贝塞尔曲线绘制遮罩图层实现如下图头像叠放效果。
关键字
Objective-C 贝塞尔曲线 反余弦
说明
项目中已有代码使用 UICollectionView
来实现横向的排列。每个头像都是一个单独的 Cell
,每个 Cell
上都有一个自定义的 UIImageView
,无需设置圆角裁成圆形。如果按照从左往右的顺序叠放,正常情况下右边的会遮挡左边的头像,这与想要的效果相悖,所以采用给右边的头像裁剪出月牙的形式来模拟被遮挡的效果。
细节
两个头像堆叠时,可以看成是两个等圆相交。在已知两个圆心距离的情况下,求出两个交点所对应圆心角的弧度,根据弧度给需要月牙形绘制Mask
遮罩。
-
下图是两个半径为 15 的圆相交,那么短弧 ADC 和长弧 ABC 所组成的区域就是我们所需要的区域。
等圆相交.png
- 根据余弦定理及反余弦函数求出交点 A 和 C 组成的圆心角弧度
此处 c 为两个圆心的距离,b 和 a 因为等圆所以相等
CGFloat angle = 2 * acos((c * c)/(2 * a * c));
-
有了圆心角的弧度,还要再确定一长一短两个弧线的起始和结束位置(两个交点)在下图中位置
radians_circle.jpeg
长弧 ABC :在 π 值上下分别加减angle
的一半
CGFloat startAngle1 = M_PI + (angle/M_PI/2) * M_PI;
CGFloat endAngle1 = M_PI - (angle/M_PI/2) * M_PI;
先调用UIBezierPath
的bezierPathWithArcCenter:
方法绘制长弧 ABC。 其中 center1
为圆心的 Point
。clockwise
采用顺时针方向。
UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:center1 radius:radius startAngle:startAngle1 endAngle:endAngle1 clockwise:YES];
- 类似的,我们求出绘制短弧 ADC 所需要的参数
短弧 ADC在 (0,2π) 附近,另外还需注意,为了两段弧线可以正确组成想要的月牙形状。短弧的起始位置需要从长弧的结束位置开始。所以和绘制长弧略有不同。
CGFloat startAngle2 = (angle/M_PI/2) * M_PI;
CGFloat endAngle2 = M_PI * 2 - (angle/M_PI/2) * M_PI;
调用UIBezierPath
的bezierPathWithArcCenter:
方法绘制短弧 ADC(CDA)。 其中 center2
为 短弧圆心的 Point
,x 轴方向距离长弧圆心距离为 c。clockwise
采用逆时针方向。
UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center2 radius:radius startAngle:startAngle2 endAngle:endAngle2 clockwise:NO];
这样一来,以长弧的结束点位置为起点绘制出短弧。两个圆弧恰好可以衔接。只需调用如下方法即可
[path1 appendPath:path2];
最后使用CAShapeLayer
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = path1.CGPath;
layer.strokeColor = [UIColor clearColor].CGColor;
self.imageView.layer.mask = layer;
设置完 mask
就能让两段圆弧组成的区域显示出月牙形的头像了。
本文开头提到头像列表采用的 UICollectionView
实现横向排列,还需要设置水平间距。其中 radius
为半径, c
为两个圆心的距离
flowLayout.minimumLineSpacing = 2 * radius - c;
网友评论