专栏名称: Cocoa开发者社区
CocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。
目录
相关文章推荐
51好读  ›  专栏  ›  Cocoa开发者社区

iOS篇-UI篇-CoreAnimation(核心动画)

Cocoa开发者社区  · 公众号  · ios  · 2017-07-29 10:59

正文

一 : 科普一分钟


我们看到很多产品都有炫酷的动画,我们会有跃跃欲试的感觉,复杂的结构拆解开各个小部分,都是有基本的动画效果组合而成,下面主要介绍一下CoreAnimation这套苹果为我们提供的功能强大的api,为我们提供了各种动画效果.配合着我们的想象力来实现各种效果.


二 : CALayer和其重要属性


CALayer 我们平时的基础控件包含UIview, 点击按钮,label,等等.这些控件之所以能显示在我们的眼前,因为这些控件上都有一个图层 CALayer


我们在创建这些基础控件时,其内部会自动创建一个图层 CALayer对象.


1.给UIView CALayer属性约束


@property (strong, nonatomic) IBOutlet UIImageView *tzImageView;


  //设置阴影的颜色

    self.tzView.layer.shadowColor = [UIColor orangeColor].CGColor;

    

     //设置阴影的不透明度

    self.tzView.layer.shadowOpacity = 1;

    

    self.tzView.layer.shadowOffset = CGSizeMake(-5, -5);

    

    //设置阴影模糊半径

    self.tzView.layer.shadowRadius = 5;

    

    //边框宽度,往里边延伸

    self.tzView.layer.borderWidth = 2;

    self.tzView.layer.borderColor = [UIColor greenColor].CGColor;

    

    //设置圆角

    

    self.tzView.layer.cornerRadius = 50;


1.给UIImageView  CALayer属性约束


@property (strong, nonatomic) IBOutlet UIImageView *tzImageView;


//设置阴影的颜色

    self.tzImageView.layer.shadowColor = [UIColor orangeColor].CGColor;

    

    //设置阴影的不透明度

    self.tzImageView.layer.shadowOpacity = 1;

    

    self.tzImageView.layer.shadowOffset = CGSizeMake(-5, -5);

    

    //设置阴影模糊半径

    self.tzImageView.layer.shadowRadius = 5;

    

    //边框宽度,往里边延伸

    self.tzImageView.layer.borderWidth = 2;

    self.tzImageView.layer.borderColor = [UIColor greenColor].CGColor;

    

    //设置圆角

    

    self.tzImageView.layer.cornerRadius = 50;

    

    //把超过根层以外的东西都剪裁掉.

    self.tzImageView.layer.masksToBounds = YES;


对于 imageView 我们设置圆角的时候 要 加一行代码 


self.tzImageView.layer.masksToBounds = YES;


这个是因为  imageView 的 layer 层 上面还有一层 contens来存放 图片 如果不加上述代码,只是对其根层设置圆角,并没有对  contens 设置


1.我们自己写一个 CALayer


CALayer *layer = [CALayer layer];

        layer.backgroundColor = [UIColor redColor].CGColor;

        layer.frame = CGRectMake(50, 50, 100, 100);

    [self.view.layer addSublayer:layer];

    

    layer.contents = (id)[UIImage imageNamed:@"tz.jpg"].CGImage;



注意 :  CAlayer 是定义在 QuartzCore框架的

CGImagerRef CGColorRef是定义在CoreGraphics

UIImage UIColor 是定义在UIKit框架中的

QuartzCoreCoreGraphics 框架是可以跨平台的在MacOSX 和 iOS 上都可以使用

为了保证移植性  QuartzCore不能使用 UIImage

UIColor 只能使用 CGImagerRef CGColorRef

所以我们通常会转一下


1.CATransform3D


我们想改变图层的形变平移等等动画是怎么做的呢,可以用这个


@property (strong, nonatomic) IBOutlet UIImageView *imageView;


参数 1 : 运动角度

参数 2 : 在 X 轴 上是否有运动,

参数 3 : 在 Y轴上是否有运动

参数 4 : 在 Z轴上是否有运动


      self.imageView.layer.transform = CATransform3DMakeRotation(M_PI, 1, 1, 0);


快速写法


 [self.imageView.layer setValue:@(100) forKeyPath:@"transform.translation.x"];


1.position 和 anchorPoint 属性


CALayer 特别重要的两个属性


position : 用来设置 CAlayer在父层中的位置 以父层左上角为原点(0,0)

anchorPoint : 又成为 锚点 ![Uploading 7BF3EA02588E10B4F139DCBEFC110CB1_994121.jpg . . .]决定CALayer身上 的那个点会在  position所指定的位置, 以自己的左上角为原点(0,0) X, 和 Y的 取值范围 0~1

默认值为 (0.5,0.5);



我们把 锚点也就是  anchorPoint 点 想象成  CALayer上的一个钉子,把父层想象成一面墙 上面有个洞 就是  position 现在那个洞在哪个地方 我们就用钉子 扎到哪个地方,这个是不是好理解了一点. 接下来用代码 来描述


@property(nonatomic,weak)CALayer *layer;


   CALayer *layer = [CALayer layer];

    layer.frame = CGRectMake(200, 200, 100, 100);

    layer.backgroundColor = [UIColor greenColor].CGColor;

  

    self.layer = layer;

    

    [self.view.layer addSublayer:layer];


接下来我们让它 进行改变 看看效果


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

  self.layer.anchorPoint = CGPointMake(0, 0);            


  self.layer.position = CGPointMake(0,0);


}



假如我们没有设置 anchorPoint 会有什么效果呢 别忘了默认是 (0.5,0.5)哦


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    

       self.layer.position = CGPointMake(0,0);


}



1.隐式动画


注意看上面的gif 可以感觉出来有动画的效果,就是移动过去的,为什么呢,这是因为 手动创建的图层都会自带一个动画效果

也就是非根层


那么什么是根层呢 每一个View 内部都默认关联一个 CALayer我们称这个layer 为RootLayer->根层


非根层 - > 手动创建的 CALayer对象都存在隐式动画


可以通过 动画事务对隐式动画进行操作


//关闭 /打开 隐式动画

 [CATransaction setDisableActions:NO];


控制隐式动画


    [CATransaction begin];

    [CATransaction setDisableActions:NO];

//动画时长

    [CATransaction setAnimationDuration:2];

    self.layer.position = CGPointMake(100, 400);

    self.layer.bounds = CGRectMake(0, 0, 90, 90);

    self.layer.backgroundColor = [UIColor redColor].CGColor;

//结束

    [CATransaction commit];


三 : CoreAnimation 和其子类



我们分析一下这个子类结构图

CAMediaTiming是它们共同遵守的一个协议

CATransition 是我们熟悉的转场动画

CABasicAnimation是一个值到另一个值

CAKeyframeAnimation一个值到多个值


1.了解


要想使用 CoreAnimation 我们先要有CALayer 因为CoreAnimation 只作用在 CALayer 上有效果

通过创建 CAAnimation对象 并且设置动画属性

最后在layer 层上添加 动画 就OK 了


2 .位移动画



 //1.创建动画对象(设置layer 的属性值)

    CABasicAnimation *anmi = [CABasicAnimation animation];

    //2.设置属性

    anmi.keyPath = @"position.x";

    anmi.toValue = @300;

    

    //动画完成时,会自动删除动画

    anmi.removedOnCompletion = NO;

    anmi.fillMode = kCAFillModeForwards;

    //    anmi.fillMode = @"forwards";

    //3.添加动画

    [self.TZview.layer addAnimation:anmi forKey:nil];


1.放大缩小动画



 //-------心跳部分

    //创建动画

    CABasicAnimation *heartanmi = [CABasicAnimation animation];

    //设置属性值

    heartanmi.keyPath = @"transform.scale";

    heartanmi.toValue = @0;

    

    //设置动画执行次数

    heartanmi.repeatCount = MAXFLOAT;

    

    //动画执行时长

    heartanmi.duration = 0.7;

    

    //自动反转效果(怎样去,怎样回)

    heartanmi.autoreverses = YES;

    

    //添加动画

    [self.heartImage.layer addAnimation:heartanmi forKey:nil];


1.指定路径位移



CAKeyframeAnimation *Anmi = [CAKeyframeAnimation animation];

    Anmi.duration = 2;

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:CGPointMake(50, 50)];

    [path addLineToPoint:CGPointMake(300, 50)];

    [path addLineToPoint:CGPointMake(300, 400)];

    Anmi.keyPath = @"position";

    Anmi.path = path.CGPath;

    [self.boheImgeView.layer addAnimation:Anmi forKey:nil];


1.删除图标动画


 CAKeyframeAnimation *boheAnmi = [CAKeyframeAnimation animation];

    //设置属性

    boheAnmi.keyPath = @"transform.rotation";

    //    boheAnmi.values = @[@(angleToRad(-5)),@(angleToRad(5))];

    

    boheAnmi.values = @[@(angleToRad(-5)),@(angleToRad(5)),@(angleToRad(-5))];

    

    //动画执行次数

    boheAnmi.repeatCount = MAXFLOAT;

    //反转

    [self.boheImgeView.layer addAnimation:boheAnmi forKey:nil];


1.转场动画



-(void)animationMove{

    //添加转场动画

    CATransition *anmi = [CATransition animation];

    

    anmi.duration = 1;

    

    //设置转场类型 立体

//    anmi.type = @"cube";

    

    //水滴

    //    anmi.type = @"rippleEffect";

    

    //翻页效果

    //    anmi.type = @"pageCurl";

    

    //平推效果

    //    anmi.type = @"push";

    

    //收缩效果

    anmi.type = @"suckEffect";

    

    //动画起始位置

    anmi.startProgress = 0.3;

    //动画结束位置

    anmi.endProgress = 0.5;

    [self.TZimageView.layer addAnimation:anmi forKey:nil];


}


点击


-(void)animationSelecImage{

    _i++;

    if (_i == 4) {

        _i = 1;

        

    }

    

NSString *imageName = [NSString stringWithFormat:@"%d",_i];

    self.TZimageView.image = [UIImage imageNamed:imageName];

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{


    [self animationSelecImage];

    

    

    [self animationMove];

    

    

}


1.复制层



@property (strong, nonatomic) IBOutlet UIView *showView;


 //复制层

    CAReplicatorLayer *rel = [CAReplicatorLayer layer];

    rel.frame = self.showView.bounds;

    [self.showView.layer addSublayer:rel];

    

//赋值份数    

rel.instanceCount = 5;

    

    

    //创建一个震动条

    

    

    CALayer *layer = [CALayer layer];

    layer.contents = (id)[UIImage imageNamed:@"dishu.jpg"].CGImage;

    layer.backgroundColor = [UIColor redColor].CGColor;

//    layer.frame = CGRectMake(0, self.showView.bounds.size.height - 100, 30, 100);

    layer.bounds = CGRectMake(0, 0, 30, 100);

    layer.anchorPoint = CGPointMake(0, 1);

    layer.position = CGPointMake(0, self.showView.bounds.size.height);

    [rel addSublayer:layer];

    

    

    //添加动画

    CABasicAnimation *anmi = [CABasicAnimation animation];

    anmi.keyPath = @"transform.scale.y";

    anmi.toValue = @0;

    anmi.repeatCount = MAXFLOAT;

    anmi.autoreverses = YES;

    anmi.duration = 0.3;

    [layer addAnimation:anmi forKey:nil];

    

    

    rel.instanceTransform = CATransform3DMakeTranslation(45, 0, 0);

    //子层动画延迟执行

    rel.instanceDelay = 1;


解析 : 有的人会对 layer.anchorPoint = CGPointMake(0, 1); 不理解 这样解释,所有的动画效果都是 围绕着锚点为中心进行动画的,默认的锚点为(0.5 , 0.5) 我们为了实现效果 要移动锚点的位置.


rel.instanceTransform = CATransform3DMakeTranslation(45, 0, 0); 这个设置的含义是 ,当我们没有设置的时候 所有的复制层全都叠加在一起,当设置后 ,对复制出来的子层做形变操作,每一个是相对于上一个子层做的形变


1.倒影效果



我们先自己定义一下关联 一下 self.view 目的是直接给我们返回一个复制层的layer


@interface TZview : UIView


@end


@implementation TZview


//返回当前UIview内容layer 类型

+(Class)layerClass{


    return  [CAReplicatorLayer class];

    

}

@end


- (void)viewDidLoad {

    [super viewDidLoad];


    self.view.backgroundColor = [UIColor lightGrayColor];

    CAReplicatorLayer *repl = (CAReplicatorLayer *)self.view.layer;

    repl.instanceCount = 2;

    

    //绕着复制曾的锚点进行旋转

    repl.instanceTransform = CATransform3DMakeRotation(M_PI, 1, 0, 0);

     

    //阴影 把所有颜色减淡

    repl.instanceRedOffset -= 0.2;

    repl.instanceGreenOffset -= 0.2;

    repl.instanceBlueOffset -= 0.2;

    repl.instanceAlphaOffset -= 0.2;

    

}


解析 : 这个的注意点 就是 instanceTransform这个属性设置时候 是  绕着复制曾的锚点进行旋转的


1.手写动画效果



想把图片换成血滴 怕有些同学不适应,仿造聂风成魔时候的feel.


首先我们要自定义一个view 替换系统 self.view 先完成手写板部分功能.


#import


@interface TZdrawView : UIView



-(void)start;


-(void)redraw;


@end


#import "TZdrawView.h"


@interface TZdrawView()

@property(nonatomic,strong)UIBezierPath *path;

@property(nonatomic,weak)CALayer *dotlayer;

@end

@implementation TZdrawView


(1) 添加手势 完成 手写板功能


-(void)awakeFromNib{

    

    [super awakeFromNib];

    

    //添加手势 创建路径

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];

    

    [self addGestureRecognizer:pan];


 UIBezierPath *path = [UIBezierPath bezierPath];

    self.path = path;


}


-(void)pan:(UIPanGestureRecognizer*)pan{


    //获取当前点

   CGPoint curp = [pan locationInView:self];

    if (pan.state == UIGestureRecognizerStateBegan) {

       

        //设置启点

        [self.path moveToPoint:curp];

        

    }else if (pan.state == UIGestureRecognizerStateChanged){

    

    

    //添加一根线到当前点

        [self.path addLineToPoint:curp];

        

        //重绘图

        [self setNeedsDisplay];

        

    }

}


-(void)drawRect:(CGRect)rect{


    //绘制路径

    [self.path stroke];

    

}


解析 : 当我们调用  [self setNeedsDisplay]; 就会触发 drawRect 方法


(2) 绘制 聂风 成魔时候的花瓣效果


首先把花瓣layer 添加上


-(void)awakeFromNib{

    

    [super awakeFromNib];

    

    //添加手势

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];

    

    [self addGestureRecognizer:pan];

    

    //添加粒子

    CALayer *dotlayer = [CALayer layer];

    dotlayer.frame = CGRectMake(0, -20, 20, 20);

//    dotlayer.backgroundColor = [UIColor redColor].CGColor;

    dotlayer.contents = (id)[UIImage imageNamed:@"flower"].CGImage;

    

    self.dotlayer = dotlayer;

    [self.layer addSublayer:dotlayer];

    


    //复制层

    CAReplicatorLayer *repl = (CAReplicatorLayer*)self.layer;

    repl.instanceCount = 30;

    //设置动画演延时执行时长

    repl.instanceDelay = 0.1;

    // //创建路径,设置启点

    UIBezierPath *path = [UIBezierPath bezierPath];

    self.path = path;

    

}


让自己成为复制层


//成为复制层

+(Class)layerClass{


    return [CAReplicatorLayer class];

    

}


开始绘制动画


-(void)start{


    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];

    anim.keyPath = @"position";

    anim.path = self.path.CGPath;

    anim.repeatCount = MAXFLOAT;

    anim.duration = 13;

    [self.dotlayer addAnimation:anim forKey:nil];

    

}


(3)重新绘制功能


-(void)redraw{



    //删除动画

    [self.dotlayer removeAllAnimations];

    

    //删除路径

    [self.path removeAllPoints];

    

    //重绘制

    [self setNeedsDisplay];

    

}


(4)最后就是把封装好的画板给我们的控制器用,这步就省略了.


四 : 实例解析未读消息移除动画



这个功能我们主要用到的一个图层叫 CAShapeLayer

这个图层的作用就是控制形变.我们先来分析一下这个功能的结构图



根据简单的 同位角角相等 和内错角相等 还有一些正余弦知识我们可以了解到 各个点的位置


解析 : 有的人会问 为什么 A点坐标 那个 为什么 y1 + r1 * sinθ

为什么不是 y1 - r1 * sinθ

因为当我们手指移动时候 这个 cosθ 是变化的 所以正负不一样,你也可以写成 y1 - r1 * sinθ 但是此时按照某一时刻的分析 我们暂且这么做.


(1)首先我们自定义一个btn 按钮


@interface TZmessageBtn : UIButton


@end


#import "TZmessageBtn.h"


@interface TZmessageBtn()

@property(nonatomic,weak)UIView *smallcircle;

@property(nonatomic,strong)CAShapeLayer *shapL;


@end


(2)添加移动手势 和 初始化视图


-(void)awakeFromNib{

    [super awakeFromNib];

    

    [self setUp];

    

    //添加手势

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];

    [self addGestureRecognizer:pan];

    

    

}


-(void)setUp{


   //圆角

    self.layer.cornerRadius = self.bounds.size.width * 0.5;

    

    

    //设置背景颜色

    [self setBackgroundColor:[UIColor blueColor]];

    

    

    [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

    

    self.titleLabel.font = [UIFont systemFontOfSize:12];

    

    

    //添加小圆

    UIView *smallcircle = [[UIView alloc]initWithFrame:self.frame];

    smallcircle.layer.cornerRadius = self.layer.cornerRadius;

    smallcircle.backgroundColor = self.backgroundColor;

    self.smallcircle = smallcircle;

    [self.superview addSubview:smallcircle];

    

    

    //把一个UIView添加到指定的位置

    

    [self.superview insertSubview:smallcircle belowSubview:self];

    

}


(3).两个圆 根据拖动计算距离


//求两个圆之间的距离


-(CGFloat)distanceWithSmallCircle:(UIView*)smallCircle BigCircle:(UIView*)bigcircle{


     //x轴方向偏移量

    CGFloat offsetX = bigcircle.center.x - smallCircle.center.x;

    

    //y轴方向偏移量


    CGFloat offsetY = bigcircle.center.y - smallCircle.center.y;


  return   sqrt(offsetX * offsetX + offsetY * offsetY);

    

}


(4)计算不规则的弧形


-(UIBezierPath*)pathWithSmallCircle:(UIView*)smallCircle BigCircle:(UIView*)bigcircle{


    CGFloat x1 = smallCircle.center.x;

    CGFloat y1 = smallCircle.center.y;

    

    CGFloat x2 = bigcircle.center.x;

    CGFloat y2 = bigcircle.center.y;

    

    CGFloat d = [self distanceWithSmallCircle:smallCircle BigCircle:bigcircle];

    

    

    if (d <= 0) {

        return nil;

        

    }

    

    

    

    //------------

    CGFloat cosθ = (y2 - y1) / d;

    CGFloat sinθ = (x2 - x1) / d;

    CGFloat r1 = smallCircle.bounds.size.width * 0.5;

    CGFloat r2 = bigcircle.bounds.size.width * 0.5;

    

    

    

    

    //描述点

    //A点

    CGPoint pointA =  CGPointMake(x1 - r1 *cosθ, y1 + r1 * sinθ);

    

    //B点

    CGPoint pointB = CGPointMake(x1 + r1 * cosθ, y1 - r1 * sinθ);

    

    //C点

    CGPoint pointC = CGPointMake(x2 + r2 * cosθ, y2 - r2 * sinθ);

    

    //D点

    

    CGPoint pointD = CGPointMake(x2 - r2 * cosθ, y2 + r2 * sinθ);

    

    //  O点

    CGPoint pointO = CGPointMake(pointA.x + d * 0.5 * sinθ, pointA.y + d * 0.5 * cosθ);

    //P点

    CGPoint pointP = CGPointMake(pointB.x + d * 0.5 * sinθ, pointB.y + d * 0.5 * cosθ);

    

    

    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;

    

}


(5)设置按钮高亮情况


// 取消高亮

-(void)setHighlighted:(BOOL)highlighted{



}


(6)懒加载 图形图层


-(CAShapeLayer *)shapL{


    if (_shapL == nil) {

        

        

        _shapL = [CAShapeLayer layer];

        _shapL.fillColor = [UIColor blueColor].CGColor;

        //形状图层

        [self.superview.layer insertSublayer:_shapL atIndex:0];


    }

    return _shapL;

}



(7)拖动事件


-(void)pan:(UIPanGestureRecognizer*)pan{


   //拖动

   CGPoint transp =  [pan translationInView:self];

    

    //transform 并没有修改center 修改的是frame

//    self.transform = CGAffineTransformTranslate(self.transform, transp.x, transp.y);

    

    CGPoint center = self.center;

    center.x += transp.x;

    center.y += transp.y;

    self.center = center;

    

    //复位

    [pan setTranslation:CGPointZero inView:self];

    

    

    CGFloat distance = [self distanceWithSmallCircle:self.smallcircle BigCircle:self];

    

    //小圆半径根据距离增大半径减小

    CGFloat smallR = self.bounds.size.width * 0.5;

    smallR -= distance/10.0;

    self.smallcircle.bounds = CGRectMake(0, 0, smallR * 2, smallR * 2);

    self.smallcircle.layer.cornerRadius = smallR ;

    

    

    //形状图层

    UIBezierPath *path = [self pathWithSmallCircle:self.smallcircle BigCircle:self];

    

    

    

    if (self.smallcircle.hidden == NO) {

        self.shapL.path = path.CGPath;

        

        

    }

         if (distance > 60) {

        //小圆隐藏,路径隐藏

        self.smallcircle.hidden = YES;

        [self.shapL removeFromSuperlayer];

             self.shapL = nil;

    }

    

    

    

   // 手指松开

    if (pan.state == UIGestureRecognizerStateEnded) {

        //判断结束时是否大于60

        if (distance >= 60) {

         //让按钮消失

            

            //播放动画消失

            UIImageView *imagev = [[UIImageView alloc]initWithFrame:self.bounds];

            [self addSubview:imagev];

            NSMutableArray *Array = [NSMutableArray array];

            for (int i = 0; i < 8; i++) {

             UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d",i+1]];

                

                [Array addObject:image];

            }

            imagev.animationImages = Array;

            [imagev startAnimating];

           

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                [self removeFromSuperview];

                

            });

        

        }else{

          //复位操作

            [self.shapL removeFromSuperlayer];

            

            self.shapL = nil;

            // 还原位置

            [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:0 options:UIViewAnimationOptionCurveLinear animations:^{

                

                //设置大圆中心点位置

                self.center = self.smallcircle.center;


            } completion:^(BOOL finished) {

                // 显示小圆

                self.smallcircle.hidden = NO;

            }];


        }

    }

    

}


解析 我们对于变化的计算方式通常是求出极值,然后再计算响应比例.


(8) 引用自定义按钮 并且 VC取消autolayout


self.view.translatesAutoresizingMaskIntoConstraints = NO;


五 : 总结


对于动画效果,我们不必过多的追求极端和完美,我们只要做好最基础的,好的效果就迎刃而解了.

我们还应该了解什么时候使用核心动画 什么时候 使用我们的UI动画


(1) 当我们动画只作用在Layer 层的时候

(2)我们核心的动画看到的都是假象,因真正的view 并没有发生变化.

(3)当我们不需要与用户进行交互的时候 使用核心动画

(4)我们使用根据路径做动画,还要转场动画时候 用核心动画.


我们先掌握这些简单的动画效果和基础知识,才能做出更漂亮的动画.


一周精选

iOS 移动端面向文档开发

一位程序媛眼中的程序员

在GitHub上最受欢迎的大多是库或框架

[iOS]终极横竖屏切换解决方案

让你成为Git和GitHub大神的20个技巧

WatchOS系统开发大全