受 Kitten 大神的一篇妙文所启发,惊觉原来风靡良久之“水滴下拉刷新”效果,可用贝塞尔曲线实现。实乃当头一棒,顿悟之清爽,妙哉妙哉。遂根据原文,加以自己所理解,调配出此文,以飨读者。
看起来似乎相当精妙,实际原理却并不复杂,甚至可算浅显。想来人们所云之人生大道理亦与此有异曲同工之妙。废话就此。
核心流程梳理如下:
- 生成二点,一上一下,成双成对,只羡鸳鸯不羡仙;
- 拖动上层点,使其分离,棒打鸳鸯,所用之棒乃
UIPanGestureRecognizer
; - 神仙无情人有情,二点相隔异地却仍藕断丝连,绘制藕丝需用
UIBezierPath
; - 坚如磐石的爱情终究被距离之滴水所穿,斩断情丝重置 UI。
好了,不装逼了✺◟(∗❛ัᴗ❛ั∗)◞✺。
难点为利用贝塞尔曲线绘制藕丝。来人啊,把原理图呈上来享用:
上方红色框所标注的,就是我们需要用贝塞尔曲线来绘制的“水滴黏性效果”的轮廓。如果还不知道贝塞尔曲线是怎么来的,可以观看此篇跪膝之文贝塞尔曲线扫盲。只要计算出红色标注的6个点坐标,贝塞尔曲线也就出来了。
关键的计算方法都在上面图中,下面看代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31- (void)reloadBezierPath
{
CGFloat r1 = self.trailDot.frame.size.width / 2.0f;
CGFloat r2 = self.headDot.frame.size.width / 2.0f;
CGFloat x1 = self.trailDot.center.x;
CGFloat y1 = self.trailDot.center.y;
CGFloat x2 = self.headDot.center.x;
CGFloat y2 = self.headDot.center.y;
CGFloat distance = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
CGFloat sinDegree = (x2 - x1) / distance;
CGFloat cosDegree = (y2 - y1) / distance;
CGPoint pointA = CGPointMake(x1 - r1 * cosDegree, y1 + r1 * sinDegree);
CGPoint pointB = CGPointMake(x1 + r1 * cosDegree, y1 - r1 * sinDegree);
CGPoint pointC = CGPointMake(x2 + r2 * cosDegree, y2 - r2 * sinDegree);
CGPoint pointD = CGPointMake(x2 - r2 * cosDegree, y2 + r2 * sinDegree);
CGPoint pointN = CGPointMake(pointB.x + (distance / 2) * sinDegree, pointB.y + (distance / 2) * cosDegree);
CGPoint pointM = CGPointMake(pointA.x + (distance / 2) * sinDegree, pointA.y + (distance / 2) * cosDegree);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:pointA];
[path addLineToPoint:pointB];
[path addQuadCurveToPoint:pointC controlPoint:pointN];
[path addLineToPoint:pointD];
[path addQuadCurveToPoint:pointA controlPoint:pointM];
self.shapeLayer.path = path.CGPath;
}
就是这么简单。完整的 Demo 已经上传到这里。当然我知道你肯定喜欢自己实现多于下载别人 Demo。
以上