博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动画-CAShapeLayer实现QQ消息红点拖拽效果
阅读量:7022 次
发布时间:2019-06-28

本文共 4268 字,大约阅读时间需要 14 分钟。

hot3.png

CAShapeLayer

一言以蔽之:CAShapeLayer 可以根据贝塞尔曲线描绘出的路径而生成对应的图形

综合例子

  • 效果图

QQ粘性动画

  • 关键技术点剖析

  • 分析 QQ 粘性动画的关键点就是当手势拖动时候2个圆之间那个形状怎么绘制

答案:将2个圆的某一时刻之间形成的形状用数学抽象来计算。 轨迹分解

  • 拖动到超过某个范围的时候怎么执行爆炸动画

UIImageView 可以执行帧动画,类似于 Flash 效果

关键代码

- (void)pan:(UIPanGestureRecognizer *)pan{    //当前移动的偏移量    CGPoint transP = [pan translationInView:self];    //改变红点的位置    //transform并没有修改自身的 center(center 是 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;}

完整的代码,

转载于:https://my.oschina.net/u/1778933/blog/1827917

你可能感兴趣的文章
分享几个.NET WinForm开源组件,纪念逐渐远去的WinForm。。。
查看>>
使用EntitysCodeGenerate
查看>>
Magicodes.WeiChat——ASP.NET Scaffolding生成增删改查、分页、搜索、删除确认、批量操作、批量删除等业务代码...
查看>>
CSDN-markdown编者LaTex数学公式
查看>>
air mobile andriod ios 页面加载控件
查看>>
js中的fadeIn()
查看>>
R树空间索引
查看>>
Lingo 做线性规划 - Operation Management Applications
查看>>
spring mvc controller间跳转 重定向
查看>>
Redmine 用户手册
查看>>
js中eval详解
查看>>
Sqlserver Sequence操作
查看>>
开发创建XMPP“发布订阅”扩展(xmpp pubsub extend)
查看>>
TCP/IP-协议族----17、应用层简单
查看>>
ZOJ1093 动态规划
查看>>
.Echo 命令中经常提到回显,是什么意思?
查看>>
MySQL在大数据Limit使用
查看>>
iOS中如何创建一个滑出式导航面板(1)
查看>>
Solr5.3.1整合IKAnalyzer
查看>>
Swift - 06 - 数值类型转换和类型别名
查看>>