利用动力系统做动画

 

   很多朋友问我为什么喜欢做iOS动画,想要做出酷炫的动画,还不如直接去学艺术算了,其实我以前也有想过这个问题,现在我对这个问题的解释是.

  1.美术上的动画是没有人机交互,事件点击的不同而产生不同的效果,就像漫画一样,也并不是说没有,只是美术设计师的重点不在于人机交互上面

  2.美术设计的乐趣更多的是艺术上的审美,而iOS的动画更多的是算法上的美,和创意上的美.

  3.最后最重要的一点就是,个人没有很好美术基础.

  好了,不讲这么多了,今天现在来向大家介绍一个有意思的动画吧,首先先声明一下,这篇博文的动画并非原创!其原版是KITTEN YANG上的THE GUIDE TO IOSANIMATIOE 上的UIDynamaticAnimator教学上所用的DEMO,想学动画的同学也可以看看这本电子书,里头有很多非常棒的动画设计方法.

  刚刚提到了UIDynamaticAnimator,那么什么是UIDynamaticAnimator呢?他是苹果至iOS7之后`为开发者提供的一套动力框架,主要用于一些动画,如重力动画,粘性动画,弹性动画,黑碰撞动画,粒子动画,今天我们就其中三个的三个行为进行分析,重力行为,碰撞行为,和粘性行为;

以下是成效图:

  

 

  是否觉得非常酷炫吊炸天,说实话,如果我不知道这一套动力系统,做这一个动画可能华几个月都做不出啦,但是有了这一套动力系统框架再利用Core Graphic绘制绳子的贝塞尔曲线,着个动画将变得非常简单,一下是这个动画的渲染了控制试图的效果图

  

  没错,看了渲染图,就一切都恍然大悟了,绳子只是一条简单的贝塞尔曲线,控制点就是两个灰色控制视图的中心点,下面是这个动画的.m文件下的封装;

  

//

//  AnimaView.m

//  ropeBallDemo

//

//  Created by 叶杨 on 16/3/25.

//  Copyright © 2016 叶景天. All rights reserved.

//

 

#import "AnimaView.h"

 

@interface AnimaView ()

 

@property (nonatomic, strong)UIDynamicAnimator *animator;

 

//卡板的gravity重力行为

@property (nonatomic, strong)UIGravityBehavior *halfViewGravity;

 

//ballImageView,两个控制视图的重力行为

@property (nonatomic, strong)UIGravityBehavior *controllViewGravity;

 

@property (nonatomic, strong)CAShapeLayer *shapeLayer;

 

//卡板视图view

@property (nonatomic, strong)UIView *halfView;

 

@property (nonatomic, strong)UIImageView *ballImageView;

 

@property (nonatomic, strong)UIView *upControllView;

 

@property (nonatomic, strong)UIView *downControllView;

 

 

@property (nonatomic, strong)UIView *middleView;

@end

 

 

 

 

@implementation AnimaView

 

 

- (instancetype)initWithFrame:(CGRect)frame

{

    self = [super initWithFrame:frame];

    if (self) {

        [self loadSubView];

    }

    return self;

}

 

- (void)loadSubView

{

    //初始化卡板

    self.halfView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height / 2)];

    self.halfView.alpha = 0.5;

    self.halfView.backgroundColor = [[UIColor alloc]initWithRed:0 green:0.5 blue:1 alpha:0.5];

    [self addSubview:self.halfView];

    

    

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]init];

    [pan addTarget:self action:@selector(panAction:)];

    [self.halfView addGestureRecognizer:pan];

    

    //初始化排球图片

    self.ballImageView = [[UIImageView alloc]initWithFrame:CGRectMake((self.bounds.size.width / 2) - 30, self.bounds.size.height / 1.5, 60, 60)];

    self.ballImageView.image = [UIImage imageNamed:@"ball.png"];

    [self addSubview:self.ballImageView];

    //为图片添加阴影;

    self.ballImageView.layer.cornerRadius = self.ballImageView.bounds.size.height / 2;

    self.ballImageView.clipsToBounds = YES;

    [self.ballImageView.layer setShadowOffset:CGSizeMake(-4, 4)];

    [self.ballImageView.layer setShadowOpacity:0.5];

    [self.ballImageView.layer setShadowRadius:5.0];

    [self.ballImageView.layer setShadowColor:[UIColor grayColor].CGColor];

    [self.ballImageView.layer setMasksToBounds:NO];

    

    //初始化中间控制试图

    self.middleView = [[UIView alloc]initWithFrame:CGRectMake(self.ballImageView.center.x - 15, 200, 30, 30)];

    [self.middleView setBackgroundColor:[UIColor clearColor]];

    [self addSubview:self.middleView];

    

    //调整中间控制试图的位置,让它处于小球和卡板view的中间偏下的位置

    [self.middleView setCenter:CGPointMake(self.middleView.center.x, (self.ballImageView.center.y-self.halfView.center.y)+15)];

    

    

    //初始化顶部控制试图

    self.upControllView = [[UIView alloc] initWithFrame:CGRectMake(self.ballImageView.center.x - 15, 200, 30, 30)];

    [self.upControllView setBackgroundColor:[UIColor clearColor]];

    [self addSubview:self.upControllView];

    //调整self.upControllView的位置

    [self.upControllView setCenter:CGPointMake(self.upControllView.center.x, (self.middleView.center.y - self.halfView.center.y) + self.halfView.center.y/2)];

    

    

    //初始化下边的控制试图

    self.downControllView = [[UIView alloc]initWithFrame:CGRectMake(self.ballImageView.center.x - 15, 200, 30, 30)];

    [self.downControllView setBackgroundColor:[UIColor clearColor]];

    [self addSubview:self.downControllView];

    [self.downControllView setCenter:CGPointMake(self.downControllView.center.x, (self.middleView.center.y - self.halfView.center.y) + self.halfView.center.y*1.5)];

    [self setUpBehavior];

}

 

- (void)setUpBehavior

{

    self.animator = [[UIDynamicAnimator alloc]initWithReferenceView:self];

    //为卡板添加重力行为

    self.halfViewGravity = [[UIGravityBehavior alloc]initWithItems:@[self.halfView]];

    [self.animator addBehavior:self.halfViewGravity];

    

    //为上边和下边的控制试图添加重力行为

    self.controllViewGravity = [[UIGravityBehavior alloc]initWithItems:@[self.ballImageView,self.upControllView,self.downControllView]];

    

    __weak AnimaView *weakSelf = self;

    

    //controllViewGravity赋值,绳子的贝塞尔曲线,将在此处绘制,每当更显animator得时候,将会重新走这个Block方法

    self.controllViewGravity.action = ^{

        UIBezierPath *path=[[UIBezierPath alloc] init];

        [path moveToPoint:weakSelf.halfView.center];

        

        //绘制绳子的贝塞尔曲线,从卡板的center到小球的center,控制点为上下两个控制视图的view.center

        [path addCurveToPoint:weakSelf.ballImageView.center controlPoint1:weakSelf.upControllView.center controlPoint2:weakSelf.downControllView.center];

        

        if (!weakSelf.shapeLayer) {

            weakSelf.shapeLayer = [[CAShapeLayer alloc] init];

            weakSelf.shapeLayer.fillColor = [UIColor clearColor].CGColor;

            weakSelf.shapeLayer.strokeColor = [UIColor colorWithRed:224.0/255.0 green:0.0/255.0 blue:35.0/255.0 alpha:1.0].CGColor;

            weakSelf.shapeLayer.lineWidth = 5.0;

            

            //Shadow

            [weakSelf.shapeLayer setShadowOffset:CGSizeMake(-1, 2)];

            [weakSelf.shapeLayer setShadowOpacity:0.5];

            [weakSelf.shapeLayer setShadowRadius:5.0];

            [weakSelf.shapeLayer setShadowColor:[UIColor blackColor].CGColor];

            [weakSelf.shapeLayer setMasksToBounds:NO];

            

            [weakSelf.layer insertSublayer:weakSelf.shapeLayer below:weakSelf.ballImageView.layer];

        }

        weakSelf.shapeLayer.path=path.CGPath;

 

    };

    

    [self.animator addBehavior:self.controllViewGravity];

    //先为卡片添加撞击行为,self.bounds的一般作为边界

    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.halfView]];

    [collision addBoundaryWithIdentifier:@"Left" fromPoint:CGPointMake(-1, 0) toPoint:CGPointMake(-1, [[UIScreen mainScreen] bounds].size.height)];

    [collision addBoundaryWithIdentifier:@"Right" fromPoint:CGPointMake([[UIScreen mainScreen] bounds].size.width+1,0) toPoint:CGPointMake([[UIScreen mainScreen] bounds].size.width+1, [[UIScreen mainScreen] bounds].size.height)];

    [collision addBoundaryWithIdentifier:@"Middle" fromPoint:CGPointMake(0, [[UIScreen mainScreen] bounds].size.height/2) toPoint:CGPointMake([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height/2)];

    [_animator addBehavior:collision];

    

    

    //最后一步,也是最关键的一步,就是为卡片view上下两个控制试图,和最下面的一个ballImageView添加,粘性行为

    //记住这里的哥哥attach设置锚点的偏移量要注意,只有锚点的偏移量设置得到好,才能够使绳子跳动起来

    UIAttachmentBehavior *attach1 =  [[UIAttachmentBehavior alloc]initWithItem:self.halfView offsetFromCenter:UIOffsetMake(1, 1) attachedToItem:self.upControllView offsetFromCenter:UIOffsetMake(0, 0)];

    [_animator addBehavior:attach1];

    UIAttachmentBehavior *attach2 = [[UIAttachmentBehavior alloc]initWithItem:self.upControllView offsetFromCenter:UIOffsetMake(0, 0) attachedToItem:self.downControllView offsetFromCenter:UIOffsetMake(0, 0)];

    [_animator addBehavior:attach2];

    

    UIAttachmentBehavior *attach3=[[UIAttachmentBehavior alloc] initWithItem:self.downControllView offsetFromCenter:UIOffsetMake(0, 0) attachedToItem:self.ballImageView offsetFromCenter:UIOffsetMake(0, -_ballImageView.bounds.size.height/2)];

    [_animator addBehavior:attach3];

    

    //最后还要给卡板和小球还有各个控制视图加一个框架.

    UIDynamicItemBehavior *PanItem=[[UIDynamicItemBehavior alloc] initWithItems:@[self.halfView,self.upControllView,self.downControllView,self.ballImageView]];

    PanItem.elasticity = 0.5;

 

    [_animator addBehavior:PanItem];

}

 

 

- (void)panAction:(UIPanGestureRecognizer *)pan

{

    CGPoint translation = [pan translationInView:pan.view];

    //

    if (!(pan.view.center.y + translation.y>(self.bounds.size.height/2)-(pan.view.bounds.size.height/2))) {

        pan.view.center=CGPointMake(pan.view.center.x, pan.view.center.y+ translation.y);

        

        

        [pan setTranslation:CGPointMake(0, 0) inView:pan.view];

    }

    

    if (pan.state==UIGestureRecognizerStateBegan) {

        [self.animator removeBehavior:self.halfViewGravity];

        //        [_animator removeBehavior:_viewsGravity];

    }

    else if (pan.state==UIGestureRecognizerStateChanged){

        

    }

    else if (pan.state==UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled || pan

             .state == UIGestureRecognizerStateFailed

             ) {

        //        self.ballImageView.center = CGPointMake(70, 100);

        

        [self.animator addBehavior:self.halfViewGravity];

        

    }

    

    //通过这个方法可以让animator重新更新它所有的动力行为

    [_animator updateItemUsingCurrentState:pan.view];

}

 

   讲了这么多,动力系统剩下的类大家就可以自己研究了,代码花了一天才敲完(主要是具体参数的调试,非常烦人)具体Demo,大家可以在我的GITHUB上下载

下载地址是

  https://github.com/bnb173yjx/DynamaticRopeBallDemo

@end

 

posted @ 2016-03-25 21:29  6Xa天  阅读(243)  评论(0编辑  收藏  举报