Files
knowledge-kit/Chapter1 - iOS/1.26.md
2020-02-25 17:46:51 +08:00

172 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CAShapeLayer
> 一言以蔽之CAShapeLayer 可以根据贝塞尔曲线描绘出的路径而生成对应的图形
## 综合例子
- 效果图
![QQ粘性动画](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QmUhGFJgxj6ofpvZp6MK3bqaH2hLgq9vfKsnwDmMisahGu.gif)
- 关键技术点剖析
- 分析 QQ 粘性动画的关键点就是当手势拖动时候2个圆之间那个形状怎么绘制
答案将2个圆的某一时刻之间形成的形状用数学抽象来计算。
![轨迹分解](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QmQUyUSLYB3VGs4juzfsEdncyWetz7BTN2GFtURbmEYbEY.png)
- 拖动到超过某个范围的时候怎么执行爆炸动画
UIImageView 可以执行帧动画,类似于 Flash 效果
### 关键代码
```
- (void)pan:(UIPanGestureRecognizer *)pan{
//当前移动的偏移量
CGPoint transP = [pan translationInView:self];
//改变红点的位置
//transform并没有修改自身的 centercenter 是 layer 的position只是修改了 frame
NSLog(@"偏移量:%@",NSStringFromCGPoint(transP));
CGPoint center = self.center;
center.x += transP.x;
center.y += transP.y;
self.center = center;
//self.transform = CGAffineTransformTranslate(self.transform, transP.x, transP.y);
//手势复位:设置坐标原点位上次的坐标
[pan setTranslation:CGPointZero inView:self];
CGFloat distance = [self distanceWith:self.smallCircle bigCircle:self];
NSLog(@"%f",distance);
CGFloat smallCircleRadius = self.bounds.size.width * 0.5;
smallCircleRadius = smallCircleRadius - distance/10;
if (smallCircleRadius < 3) {
smallCircleRadius = 3;
}
self.smallCircle.bounds = CGRectMake(0, 0, smallCircleRadius*2, smallCircleRadius*2);
self.smallCircle.layer.cornerRadius = smallCircleRadius;
if (self.smallCircle.hidden == NO) {
//返回一个不规则的路径
UIBezierPath *path = [self drawTracertWithSmallCircle:self.smallCircle bigCircle:self];
//将形状转换为一个形状图层
self.shapeLayer.path = path.CGPath;//根据路径生成形状
}
//创建形状图层
[self.superview.layer insertSublayer:self.shapeLayer atIndex:0];
if (distance > 60) {
self.smallCircle.hidden = YES;
[self.shapeLayer removeFromSuperlayer];
}
if (pan.state == UIGestureRecognizerStateEnded) {
//结束手势
if (distance < 60) {
[self.shapeLayer removeFromSuperlayer];
self.center = self.smallCircle.center;
self.smallCircle.hidden = NO;
}
else{
//手势拖拽超过60则播放一个动画
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds];
NSMutableArray *images = [NSMutableArray array];
for (int i=0; i<8; i++) {
NSString *imageName = [NSString stringWithFormat:@"%d",i+1];
UIImage *image = [UIImage imageNamed:imageName];
[images addObject:image];
}
imageView.animationImages = images;
[imageView setAnimationDuration:1];
[imageView startAnimating];
[self addSubview:imageView];
//动画结束移除本身
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self removeFromSuperview];
});
}
}
}
- (CGFloat )distanceWith:(UIView *)smallCircle bigCircle:(UIView *)bigScirle{
CGFloat offsetX = bigScirle.frame.origin.x - smallCircle.frame.origin.x;
CGFloat offsetY = bigScirle.frame.origin.y - smallCircle.frame.origin.y;
return sqrt( pow(offsetX, 2) + pow(offsetY, 2));
}
//将2个圆运行的变化轨迹用代码模拟
- (UIBezierPath *)drawTracertWithSmallCircle:(UIView *)smallCircle bigCircle:(UIView *)bigCircle{
CGFloat X1 = smallCircle.center.x;
CGFloat X2 = bigCircle.center.x;
CGFloat Y1 = smallCircle.center.y;
CGFloat Y2 = bigCircle.center.y;
CGFloat r1 = smallCircle.bounds.size.width/2;
CGFloat r2 = bigCircle.bounds.size.width/2;
CGFloat d = [self distanceWith:smallCircle bigCircle:bigCircle];
//Ø 代表角度
CGFloat SinØ = (X2 - X1)/d;
CGFloat CosØ = (Y2 - Y1)/d;
CGPoint pointA = CGPointMake(X1 - r1*CosØ, Y1 + r1*SinØ);
CGPoint pointB = CGPointMake(X1 + r1*CosØ, Y1 - r1*SinØ);
CGPoint pointC = CGPointMake(X2 + r2*CosØ, Y2 - r2*SinØ);
CGPoint pointD = CGPointMake(X2 - r2*CosØ, Y2 + r2*SinØ);
CGPoint pointO = CGPointMake(X1 + SinØ *d/2, Y1 + CosØ*d/2);
CGPoint pointP = CGPointMake(X1 + SinØ *d/2,Y1 + CosØ*d/2 );
//描述路径
UIBezierPath *path = [UIBezierPath bezierPath];
//AB
[path moveToPoint:pointA];
[path addLineToPoint:pointB];
//BC(曲线)
[path addQuadCurveToPoint:pointC controlPoint:pointP];
//CD
[path addLineToPoint:pointD];
//DA(曲线)
[path addQuadCurveToPoint:pointA controlPoint:pointO];
return path;
}
```
完整的代码,[Github地址](https://github.com/FantasticLBP/BlogDemos/tree/master/QQ粘性动画)