iOS基础全面分析之四(动画全面分析)

iOS动画

好的应用都有一个共同的特点,那就是良好的用户体验,动画作为提升用户体验一个重要技术,在开发人员和产品设计人员手里,则应该受到足够重视。

CoreGraphics:

它是ios的核心图形库,平时使用最频繁的point,size,rect等这些图形,都定义在这个框架中,类名以CG开头的都属于CoreGraphics框架,它提供的都是C语言的函数接口,是可以在ios和mac os通用的。

QuartzCore:

这个框架的名称感觉不是很清晰,不明确,但是看它的头文件可以发现,它其实就是CoreAnimation,这个框架的头文件只包含了CoreAnimation.h

Core animation(核心动画)

锚点anchorPoint

  • 概念
    • anchorPoint是相对于自身layer,anchorPoint点(锚点)的值是用相对bounds的比例值来确定的。
    • anchorPoint相当于支点,可以用作旋转变化、平移、缩放,如果修改anchorPoint则layer的frame会发生改变,position不会发生改变.
    • 修改position与anchorPoint中任何一个属性都不影响另一个属性.
  • 单位:
    • 0~1
  • anchorPoint和position的关系
    • anchorPoint和position不是一个点
  • anchorPoint和position和frame的三条关系
    • 第一条关系说明:锚点不变时,frame改变,position会随着变化
    • 第二条关系说明:锚点不变时,position变化,frame会随着变化
    • 第三条关系说明:锚点改变, position不影响,frame会随着变化

创建动画的三个步骤

  • 创建核心动画大致分为三个步骤:
    1. 初始化动画对象
    2. 设置需要修改动画的属性值
    3. 把动画添加到layer上

隐式动画和显示动画

当动画完成以后你看到的都是假象,你的view并没有变化,layer分为两层:

  • presentationlayer 呈现成
    • 凡是眼睛看到的都是呈现层
  • modelayer 模型层
    • 用来存储数据,等到屏幕需要刷新的时候绘制到呈现层

显示动画

  • 通过自定义三步骤的动画都是显示动画

隐式动画

  • 通过自创建的layer,修改其属性会默认添加一些动画效果,这些动画效果就是隐式动画
    • CALayer 默认时间 0.25s(位置、颜色、大小)
    • 必须是独立的CALayer才有隐式动画, UIView的根layer是没有的

例如代码如下:


_layer = [CALayer layer];
_layer.frame = CGRectMake(200, 100, 100, 100);
//可移值性
_layer.backgroundColor = [UIColor yellowColor].CGColor;
[self.view.layer addSublayer:_layer];

_layer.frame = CGRectMake(200, 400, 100, 100);

iOS动画框架结构

iOS基础全面分析之四(动画全面分析)_第1张图片
CoreAnimation.png

在iOS系统中给我们提供了基于Core animation这几种动画,如下图所示:

iOS基础全面分析之四(动画全面分析)_第2张图片

CABasicAnimation(基本动画)

CABasicAnimation的属性

属性 说明
duration 动画的时长
repeatCount 重复的次数
repeatDuration 设置动画的时间,在改时间内一直执行,不计算次数
beginTime 指定动画开始时间
timingFunction 设置动画的速度变化
autoreverses 动画结束是否执行逆动画
fromValue 属性的起始值
toValue 结束的值
byValue 改变属性相同起始值的改变量

CABasicAnimation的Keypath属性

apple官网动画属性

如下常用的属性:

Keypath 说明 使用
transform.scale 比例转化 @(cgfloat)
transform.scale.x 宽的比例 @(cgfloat)
transform.scale.y 高的比例 @(cgfloat)
transform.rotation.x 围绕x轴旋转 @(M_PI)
transform.rotation.y 围绕y轴旋转 @(M_PI)
transform.rotation.z 围绕z轴旋转 @(M_PI)
cornerRadius 圆角的设置 @(50)
backgroundColor 背景颜色的变化 (id)[uicolor redcolor].cgcolor
bounds 大小,中心不变 [nsvalue valuewithcgrect:]
position 位置(中心点的改变) [nsvalue valuewithcgpoint]
contents 内容(比如图片) (id)image.cgimage
opacity 透明度 @(cgfloat)
contentsRect.size.width 横向拉伸缩放(需要设置contents) @(cgfloat)

CABasicAnimation的例子

做一个从上往下走的动画

CABasicAnimation *basicani = [CABasicAnimation animationWithKeyPath:@"position.y"];//中心点
basicani.toValue = @400;
basicani.duration = 2;
//动画完成不移除状态
basicani.removedOnCompletion = NO;
//保持最后的状态
basicani.fillMode = kCAFillModeForwards;
basicani.delegate = self;
[_RedView.layer addAnimation:basicani forKey:@""];

CAKeyframeAnimation关键帧动画

CAKeyframeAnimation设置动画的路径分为两种

  1. 设置path
  2. 设置一组的values

CAKeyframeAnimation的例子

代码如下:设置了一个飞机按照轨迹飞行的动画

//贝塞尔曲线
/*
 想要通过程序写曲线或者不规则的图形时,是很复杂的
 贝塞尔曲线就是通过代码转换成公式来进行绘制的。
 
 起点
 终点
 2个控制点
 **/
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(20, 200)];
[path addCurveToPoint:CGPointMake(300, 200) controlPoint1:CGPointMake(100, 100) controlPoint2:CGPointMake(200, 300)];
    
CALayer *planelayer = [CALayer layer];
planelayer.backgroundColor = [UIColor redColor].CGColor;
planelayer.frame = CGRectMake(0, 0, 40, 40);
planelayer.anchorPoint = CGPointMake(0.5, 0.8);
planelayer.contents = (id)[UIImage imageNamed:@"feiji"].CGImage;
[self.view.layer addSublayer:planelayer];
    
//需要添加到layer上
//形状图 矢量图 这个事layer的子类,CAShapeLayer有一个硬件加速更快
CAShapeLayer *shapelayer = [CAShapeLayer layer];
shapelayer.path = path.CGPath;
shapelayer.fillColor = nil;  //填充颜色
shapelayer.strokeColor = [UIColor blueColor].CGColor;//画笔的颜色
[self.view.layer addSublayer:shapelayer];
    
/*
 CAKeyframeAnimation 设置动画的路径分为两种:
 1. 设置path
 2. 设置一组values
 ***/
    
//飞行动画
CAKeyframeAnimation *planeAni = [CAKeyframeAnimation animation];
planeAni.keyPath = @"position";
planeAni.path = path.CGPath;
planeAni.rotationMode = kCAAnimationRotateAuto;
planeAni.duration = 3.5;
planeAni.fillMode = kCAFillModeForwards;
planeAni.removedOnCompletion = NO;
[planelayer addAnimation:planeAni forKey:@"planeAni"];

CAAnimationGroup动画组

将多个动画合并到一起的动画就是CAAnimationGroup动画组

CAAnimationGroup例子

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(20, 200)];
[path addCurveToPoint:CGPointMake(300, 200) controlPoint1:CGPointMake(100, 100) controlPoint2:CGPointMake(200, 300)];
    
CALayer *colorlayer = [CALayer layer];
colorlayer.frame = CGRectMake(0, 0, 60, 60);
colorlayer.position = CGPointMake(50, 200);
colorlayer.backgroundColor = [UIColor yellowColor].CGColor;
[self.view.layer addSublayer:colorlayer];

//飞行动画
CAKeyframeAnimation *planeAni = [CAKeyframeAnimation animation];
planeAni.keyPath = @"position";
planeAni.path = path.CGPath;
planeAni.rotationMode = kCAAnimationRotateAuto;
    
//改变大小
CABasicAnimation *sizeanim = [CABasicAnimation animation];
sizeanim.keyPath = @"transform.scale";
sizeanim.toValue = @0.5;

//改变颜色
CGFloat redcolor = arc4random() % 255 / 255.0f;
CGFloat greencolor = arc4random() % 255 / 255.0f;
CGFloat bluecolor = arc4random() % 255 / 255.0f ;
UIColor *color = [UIColor colorWithRed:redcolor green:greencolor blue:bluecolor alpha:1];
    
CABasicAnimation *colorAnim = [CABasicAnimation animation];
colorAnim.keyPath = @"backgroundColor";
colorAnim.toValue = (id)color.CGColor;
    
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = @[planeAni, sizeanim, colorAnim];
group.duration = 4.0f;
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[colorlayer addAnimation:group forKey:nil];

转场动画

CATransition转场动画

CATransition是CAAnimation的子类,用于过渡动画或转场动画。为视图层移入移除屏幕提供转场动画。

简单的转场动画ImageView的切换:


@property (weak, nonatomic) IBOutlet UIImageView *ImageView;
@property (strong,nonatomic)NSArray *images;
@property (assign,nonatomic)NSInteger index;


- (void)Createtransition{
    
    if(_index == 3){
        _index = 0;
    }
    _index ++ ;
    NSString *imagename = _images[_index];
    _ImageView.image = [UIImage imageNamed:imagename];
    CATransition *anima = [CATransition animation];
    anima.type = @"cube";
    [_ImageView.layer addAnimation:anima forKey:@"CATransitionkey"];
    
    
}
_images = @[@"1.jpg",@"2.jpg",@"3.jpg",@"4.jpg"];
_index = 0;

[self Createtransition];

转场动画的重要属性

  • type:系统自带转场动画的类型

    • 官方自定
    CA_EXTERN NSString * const kCATransitionFade;
    CA_EXTERN NSString * const kCATransitionMoveIn;
    CA_EXTERN NSString * const kCATransitionPush;
    CA_EXTERN NSString * const kCATransitionReveal;
    
    • 私有的type:
    NSString *const kCATransitionCube = @"cube"; 
    NSString *const kCATransitionSuckEffect = @"suckEffect"; 
    NSString *const kCATransitionOglFlip = @"oglFlip"; 
    NSString *const kCATransitionRippleEffect = @"rippleEffect"; 
    NSString *const kCATransitionPageCurl = @"pageCurl"; 
    NSString *const kCATransitionPageUnCurl = @"pageUnCurl"; 
    NSString *const kCATransitionCameraIrisHollowOpen = @"cameraIrisHollowOpen";
    NSString *const kCATransitionCameraIrisHollowClose = @"cameraIrisHollowClose";
    
  • subtype:动画类型的方向

CA_EXTERN NSString * const kCATransitionFromRight;
CA_EXTERN NSString * const kCATransitionFromLeft;
CA_EXTERN NSString * const kCATransitionFromTop;
CA_EXTERN NSString * const kCATransitionFromBottom;

transitionFromViewController

转场动画的type

UIViewAnimationOptionTransitionNone            = 0 << 20, // default
UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20,
UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20,
UIViewAnimationOptionTransitionCurlUp          = 3 << 20,
UIViewAnimationOptionTransitionCurlDown        = 4 << 20,
UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20,
UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20,
UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20,
AViewController *a = self.childViewControllers[0];
BViewController *b = self.childViewControllers[1];
CViewController *c = self.childViewControllers[2];

[self transitionFromViewController:_currentViewController
                  toViewController:b
                          duration:0.5
                           options:UIViewAnimationOptionTransitionFlipFromRight
                        animations:^{

} completion:^(BOOL finished) {

}];

Transition Animation(自定义转场动画)

第一种:presented& Dismiss
需要实现UIViewController中的UIViewControllerTransitioningDelegate协议,实现下面两个API:

//presented会调用的方法
- (nullable id ) v:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
//Dismiss会调用的方法
- (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed

第二种:Push&Pop

需要实现navigationController中的UINavigationControllerDelegate协议,实现下面一个API:

- (nullable id )navigationController:(UINavigationController *)navigationController
                                            animationControllerForOperation:(UINavigationControllerOperation)operation
                                                         fromViewController:(UIViewController *)fromVC
                                                           toViewController:(UIViewController *)toVC{

上述API的返回值id 就是我们需要自定义的动画

  • 自定义转场动画步骤:

    1. 创建一个NSObject的对象

    2. 核心:遵守

    3. 实现下面2个方法:

      //动画持续时间,单位是秒
      - (NSTimeInterval)transitionDuration:(id )transitionContext {
      }
      
      //动画效果
      - (void)animateTransition:(id )transitionContext {
      }
      
    4. animateTransition方法中实现你的动画

    5. 动画结束后调用completeTransition告诉系统转场动画结束

  • 自定义转场动画的核心思想

    • containerView 动画的容器
    • ToVC
    • FromVC
    • mask
    • completeTransition动画完成

Push&Pop形式转场动画

  • 自定义转场动画入口:

    1. 在Push和Pop的ViewController遵守UINavigationControllerDelegate协议

    2. 实现下面方法,并返回自定义动画:

      )navigationController:(UINavigationController *)navigationController
                                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                                               fromViewController:(UIViewController *)fromVC
                                                                 toViewController:(UIViewController *)toVC{
          
          if(operation == UINavigationControllerOperationPush){
              //Push
              return 返回你的自定义动画
          }
          if(operation == UINavigationControllerOperationPop){
              //Pop
              return 返回你的自定义动画
          }
          return nil;
      }
      
  • 自定义转场动画实现代码:

//Pop
- (void)CreatePopAnimation:(id )transitionContext{
    
    UIViewController * fromVC   = [_context viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC      = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *containerView       = [transitionContext containerView];
    [containerView addSubview:toVC.view];
    [containerView addSubview:fromVC.view];

    maskLayer.path              = SmallPath.CGPath;
    fromVC.view.layer.mask      = maskLayer;
    
    CABasicAnimation *anim      = [CABasicAnimation animation];
    anim.keyPath                = @"path";
    anim.fromValue              = (__bridge id _Nullable)(BigPath.CGPath);
    anim.toValue                = (__bridge id)(SmallPath.CGPath);
    anim.duration               = [self transitionDuration:_context];
    anim.timingFunction         = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.delegate               = self;
    [maskLayer addAnimation:anim forKey:nil];
    
}

//push
- (void)CreatePushAnimation:(id )transitionContext{
    
    UIViewController *toVC      = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *containerView       = [transitionContext containerView];
    [containerView addSubview:toVC.view];

    maskLayer.path              = BigPath.CGPath;
    toVC.view.layer.mask        = maskLayer;

    CABasicAnimation *anim      = [CABasicAnimation animationWithKeyPath:@"path"];
    anim.fromValue              = (__bridge id)(SmallPath.CGPath);
    anim.toValue                = (__bridge id)((BigPath.CGPath));
    anim.duration               = [self transitionDuration:_context];
    anim.timingFunction         = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.delegate               = self;
    [maskLayer addAnimation:anim forKey:nil];
}

Presentation&Dismiss形式转场动画

  • 自定义转场动画入口:

    1. present后的视图ToVC遵守UIViewControllerTransitioningDelegate协议
      • self.transitioningDelegate = self;
      • self.modalPresentationStyle = UIModalPresentationCustom;
    2. 实现下面方法,并返回自定义动画:
    - (nullable id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
    }
    
    - (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed{
    }
    
  • 自定义动画代码实现

//dissmiss
- (void)CreateDismissAnimation:(id )transitionContext{
    
    UIView* containerView   = [transitionContext containerView];
    TwoVC * fromVC          = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
     [containerView addSubview:fromVC.view];
    
    maskLayer.path              = SmallPath.CGPath;
    fromVC.view.layer.mask      = maskLayer;

    CABasicAnimation *anim      = [CABasicAnimation animation];
    anim.keyPath                = @"path";
    anim.fromValue              = (__bridge id _Nullable)(BigPath.CGPath);
    anim.toValue                = (__bridge id _Nullable)(SmallPath.CGPath);
    anim.duration               = [self transitionDuration:_context];
    anim.timingFunction         = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.delegate               = self;
    [maskLayer addAnimation:anim forKey:nil];
  
}

//Presentation
- (void)CreatePresentationAnimation:(id )transitionContext{
    
    UIViewController *toVC      = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    toVC.view.frame             = CGRectMake(0, 0, GGScreenwidth, GGScreenheight);
    UIView *containerView       = [transitionContext containerView];
    [containerView addSubview:toVC.view];
    
    maskLayer.path              = BigPath.CGPath;
    toVC.view.layer.mask        = maskLayer;

    CABasicAnimation *anim      = [CABasicAnimation animation];
    anim.keyPath                = @"path";
    anim.fromValue              = (__bridge id _Nullable)(SmallPath.CGPath);
    anim.toValue                = (__bridge id _Nullable)(BigPath.CGPath);
    anim.duration               = [self transitionDuration:_context];
    anim.timingFunction         = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.delegate               = self;
    [maskLayer addAnimation:anim forKey:nil];
}

转场动画代码 我已经集成了Push&Pop和Present&Dismiss,码字不容易,码代码更不容易,github顺手给个星星

转场效果:

iOS基础全面分析之四(动画全面分析)_第3张图片

你可能感兴趣的:(iOS基础全面分析之四(动画全面分析))