iOS动画系列一

前言:做相关demo动画已经有一段时间了、现在闲下来记录下相关动画制作。iOS动画主要就是路径动画、帧动画、缩放动画、以及这些动画的组合叫组合动画。另外还有一些3D动画和转场动画。不想看原理的直接下载demo使用方式很简单。

摇杆(手柄)制作

首先需要绘制摇杆的范围我这画了一个圆形、然后监听用户的手势、根据手势移动的前后位置判断移动的方向上、下、左、右。此外如果你规定用户只能上下或者左右移动、不能斜角移动、你可以根据移动的位置判断当前点和中心点这条直线的斜率偏移不能超过多少度。
效果如下:


handshank.gif

1.绘制背景边界圆

CGContextRef context = UIGraphicsGetCurrentContext();
//     CGContextSetRGBFillColor (context,  1, 0, 0, 1.0);//设置填充颜色
   CGContextSetRGBStrokeColor(context,143/255.0,190/255.0,81/255.0,1.0);//画笔线的颜色
   CGContextSetLineWidth(context, 2.0);//线的宽度
   bigRadius = LL_mmWidth(self)/2.0-4;
   CGContextAddArc(context, LL_mmWidth(self)/2.0, LL_mmHeight(self)/2.0, bigRadius, 0, 2*PI, 0); //添加一个圆
   CGContextDrawPath(context, kCGPathStroke); //绘制路径

2.绘制中间摇杆圆和四个方向标志以及添加摇杆手势监听。

-(void)createCenterCircle:(CGRect)selfFrame
{
   //中间摇杆圆
   _centerView = [[UIView alloc]init];
   _centerView.frame = CGRectMake((CGRectGetWidth(selfFrame)-CGRectGetWidth(selfFrame)/3.0)/2.0, (CGRectGetHeight(selfFrame)-CGRectGetHeight(selfFrame)/3.0)/2.0, CGRectGetWidth(selfFrame)/3.0, CGRectGetHeight(selfFrame)/3.0);
   _handShankOriginCenter = _centerView.center;
   smallRadius = (CGRectGetWidth(selfFrame)/3.0)/2.0;
   _centerView.layer.cornerRadius = smallRadius;
   _centerView.layer.masksToBounds = YES;
   _centerView.alpha = 0.8;
   
   _centerView.backgroundColor = [UIColor colorWithRed:143/255.0 green:190/255.0 blue:81/255.0 alpha:1.0];
   [self addSubview:_centerView];
   //四个方向标志
   float interval = (CGRectGetHeight(selfFrame)-LL_mmHeight(_centerView))/4.0;
   for (int i = 0; i<4; i++) {
       UIImageView *arrow = [self InsertImageView:self cgrect:CGRectMake(0, 0, 20*FIT_WIDTH, 12*FIT_WIDTH) image:[UIImage imageNamed:self.handShankArrows[i]]];
//        InsertImageView(self, CGRectMake(0, 0, 20*FIT_WIDTH, 12*FIT_WIDTH), [UIImage imageNamed:self.handShankArrows[i]]);
//        arrow.hidden = YES;//注意隐藏箭头了
       switch (i) {
           case 0:
           {
               //上
                arrow.center = CGPointMake(CGRectGetWidth(selfFrame)/2.0, interval);
               
           }
               break;
           case 1:
               //下
               arrow.center = CGPointMake(CGRectGetWidth(selfFrame)/2.0, CGRectGetHeight(selfFrame)-interval);
               break;
           case 2:
               //左
               arrow.frame = CGRectMake(0, 0, 12*FIT_WIDTH, 20*FIT_WIDTH);
               arrow.center = CGPointMake(interval, CGRectGetHeight(selfFrame)/2.0);
               break;
           case 3:
               //右
               arrow.frame = CGRectMake(0, 0, 12*FIT_WIDTH, 20*FIT_WIDTH);
               arrow.center = CGPointMake(CGRectGetWidth(selfFrame)-interval, CGRectGetHeight(selfFrame)/2.0);
               break;
               
           default:
               break;
       }
       
       
       
   }
  
   //摇杆添加移动手势
   UIPanGestureRecognizer *pangesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pangestureAction:)];
   [_centerView addGestureRecognizer:pangesture];
}

3.分析手势数据根据上一次移动的点和这次的做比较判断移动方向

-(void)pangestureAction:(UIPanGestureRecognizer *)recognizer
{
   CGPoint translation = [recognizer translationInView:self];
   [recognizer setTranslation:CGPointZero inView:self];
   CGPoint movingPosition = CGPointMake(recognizer.view.center.x + translation.x,
                                   recognizer.view.center.y + translation.y);
   
   int rangeRadius = bigRadius - smallRadius;
   if ([self isInciclelPoint:movingPosition andR:rangeRadius centrePoing:_handShankOriginCenter]) {
       _lasrtPoint = movingPosition;
       _centerView.center = _lasrtPoint;
       
       if (_lasrtPoint.y < _startPoint.y && (fabsf((float)(_lasrtPoint.y - _startPoint.y)) > fabs(_lasrtPoint.x - _startPoint.x))) {
           //上
           if (_currentDirection == HandShankDirectionUnknow) {
               NSLog(@"开始上");
               _currentDirection = HandShankDirectionStartTop;
           }else{
               NSLog(@"上");
               _currentDirection = HandShankDirectionTop;
           }
          
       }else if (_lasrtPoint.y > _startPoint.y && (fabsf((float)(_lasrtPoint.y - _startPoint.y)) > fabs(_lasrtPoint.x - _startPoint.x)))
       {
           if (_currentDirection == HandShankDirectionUnknow) {
               NSLog(@"开始下");
               _currentDirection = HandShankDirectionStartDown;
           }else{
               NSLog(@"下");
               _currentDirection = HandShankDirectionDown;
           }
           
       }else if (_lasrtPoint.x >_startPoint.x && (fabsf((float)(_lasrtPoint.x -_startPoint.x)) > fabsf((float)(_lasrtPoint.y -_lasrtPoint.y))) )
       {
           if (_currentDirection == HandShankDirectionUnknow) {
               NSLog(@"开始右");
                _currentDirection = HandShankDirectionStartRight;
           }else{
               NSLog(@"右");
               _currentDirection = HandShankDirectionRight;
           }
           
       }else if (_lasrtPoint.x <_startPoint.x && (fabsf((float)(_lasrtPoint.x -_startPoint.x)) > fabsf((float)(_lasrtPoint.y -_lasrtPoint.y))) )
       {
           if (_currentDirection == HandShankDirectionUnknow) {
               NSLog(@"开始左");
               _currentDirection = HandShankDirectionStartLeft;
           }else{
               NSLog(@"左");
               _currentDirection = HandShankDirectionLeft;
           }
           
       }
       
       if (self.delegete && [self.delegete respondsToSelector:@selector(handShankDirectionDidChange:)]) {
           [self.delegete handShankDirectionDidChange:_currentDirection];
       }
   }
   
   if(recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateFailed)
   {
       NSLog(@"结束");
       _startPoint = _handShankOriginCenter;
       [UIView animateWithDuration:0.5 animations:^{
           _centerView.center = _handShankOriginCenter;
       }];
       _currentDirection = HandShankDirectionUnknow;
       
       
       if (self.delegete && [self.delegete respondsToSelector:@selector(handShankDirectionDidEnd)]) {
           [self.delegete handShankDirectionDidEnd];
       }
   }
  
   
   
}

饼状图绘制

前言:饼状图由三角弧组成、弧线有起始角度和末尾角度组成、所以可以用一个mode类记录相关信息。然后绘制三角弧。效果如下:


pichart.gif

1.弧线贝塞尔路径写法

-(UIBezierPath *)bezierPathStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle
{
    UIBezierPath *path = [UIBezierPath new];
    [path moveToPoint:_centerPoint];
    [path addArcWithCenter:_centerPoint radius:_radius startAngle:DEGREES_TO_RADIANS(startAngle) endAngle:DEGREES_TO_RADIANS(endAngle) clockwise:YES];
    [path closePath];
    return path;
}

2.生成弧线和对应的文字

-(void)createPieChartView
{
    [self.models enumerateObjectsUsingBlock:^(CurveModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        UIBezierPath *path = [self bezierPathStartAngle:obj.startAngel endAngle:obj.endAngel];
        CAShapeLayer *trangleLayer = [CAShapeLayer layer];
        //        maskLayer.backgroundColor = [UIColor purpleColor].CGColor;
        trangleLayer.path = [path CGPath];
        trangleLayer.fillColor = obj.color.CGColor;
        trangleLayer.fillRule = kCAFillRuleNonZero;//kCAFillRuleEvenOdd画的区域 取反  解释为奇偶。
        [self.layer addSublayer:trangleLayer];
        obj.trangleLayer = trangleLayer;
        
         CGFloat angle = obj.endAngel-(obj.endAngel-obj.startAngel)/2.0;//扇形边缘中心位置的角度
        //扇形边缘的中心点
//        CGPoint aPoint = CGPointMake(_centerPoint.x+ _radius*cos(DEGREES_TO_RADIANS(angle)),_centerPoint.y+ _radius*sin(DEGREES_TO_RADIANS(angle)));
        //外面边缘的半径
        CGFloat outRadius = [self height]/2.0+100;//100是随意
        CGPoint outCenterPoint = CGPointMake(_centerPoint.x+ outRadius*cos(DEGREES_TO_RADIANS(angle)), _centerPoint.y+outRadius*sin(DEGREES_TO_RADIANS(angle)));
        obj.outCenterPoint = outCenterPoint;
        
        int width = 30;
        //内部边缘文字
        UILabel *label0 = [[UILabel alloc]init];
        label0.adjustsFontSizeToFitWidth = YES;
        label0.bounds = CGRectMake(0, 0, width, width);
        CGFloat newRadius0 = (_radius-((width/2.0)/cos(DEGREES_TO_RADIANS(45))));//扇形的半径+label的对角线长度
        //新半径扇形的边缘中心点
        CGPoint bPoint0 = CGPointMake(_centerPoint.x+ newRadius0*cos(DEGREES_TO_RADIANS(angle)), _centerPoint.y+newRadius0*sin(DEGREES_TO_RADIANS(angle)));
        obj.innerLabelCenterPoint = bPoint0;
        obj.innerLabe = label0;
        label0.center = outCenterPoint;
        label0.text = @"6";
        label0.textAlignment = NSTextAlignmentCenter;
        [self addSubview:label0];
        
        
        //外围边缘文字
        UILabel *label = [[UILabel alloc]init];
        label.text = @"%10";
        label.textAlignment = NSTextAlignmentCenter;
        label.adjustsFontSizeToFitWidth = YES;
        label.bounds = CGRectMake(0, 0, width, width);
        CGFloat newRadius = (_radius+((width/2.0)/cos(DEGREES_TO_RADIANS(45))));//扇形的半径+label的对角线长度
        //新半径扇形的边缘中心点
        CGPoint bPoint = CGPointMake(_centerPoint.x+ newRadius*cos(DEGREES_TO_RADIANS(angle)), _centerPoint.y+newRadius*sin(DEGREES_TO_RADIANS(angle)));
        obj.outLabelCenterPoint = bPoint;
        obj.outLabel=label;
        label.center = outCenterPoint; //CGPointMake( aPoint.x+width/2.0, aPoint.y+((width/2.0)*tan(DEGREES_TO_RADIANS(angle))));
        [self addSubview:label];
        
    }];
    
}

3.添加简单翻转动画和路径动画

-(void)startAnimation
{
    //翻转 oglFlip
   [CommonUse addAnimationLayer:self.layer type:@"oglFlip"];
    
    [self.models enumerateObjectsUsingBlock:^(CurveModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [self startLabelAnimation:obj];
    }];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self stopAnimation];
    });
}

传送门:

源码
有疑问的小伙伴欢迎加交流讨论QQ:206931384

喜欢的小伙伴们在我git上给个star感激不尽、目前正在持续更新中喜欢关注的和建议小伙伴可以fork一下。你的赞美是我努力的源泉我会加油的!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,960评论 3 119
  • 打扫干净的房间,春阳刚刚好 茶香渐浓 假想谁会第一个到来 那一只麻雀已错过列车 双飞燕早回绝 会是谁呢 这一杯春茶...
    栋间塘阅读 195评论 0 0
  • 今天早操送孩子上学后去上班,默默观察自己对同事的态度,和同事对我的态度。想找到能够走进同事、客户心里的那个人,我也...
    TA77范丽萍阅读 129评论 1 2
  • 最近很多想学UI设计的小白同学来咨询我,说现在那么多人学UI设计,我去学 还有前途吗? 对于这个问题根据我对这个行...
    UI设计江老师阅读 1,299评论 0 0
  • 轻轻站立,微闭双眼,静静地与自己相处,眼前一片黑暗,世界在我心里。 我听见海水缓缓拍打礁石,远处的...
    紫心姐姐阅读 715评论 0 0