动画基础

2016-08-16  本文已影响29人  wpf_register

某种意义 上苹果已经提供了优美简洁的UIView接口,对简单需求没必要处理CALayer,因为苹果已经通过UIView 的高级API 间接地使得动画变得很简单。
但简单就不可避免地带来灵活上的缺陷,UIView 没有暴露CALayer的功能:

  1. 阴影,圆角,带颜色的边框
  2. 3D 变换
  3. 非矩形范围
  4. 透明遮罩
  5. 多级非线性动画

基础属性

UIImage *image = [UIImage imageNamed:@"1.jpg"];
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(0, 0, 300, 400);
[self.view.layer addSublayer:layer];
self.myLayer = layer;

//1.contents 属性(id 类型)
//image.CGImage 返回一个CGImageRef 指向CGImage结构的指针
//CGImageRef 不是Cocoa对象,而是一个Core Foundation 类型,需要 __bridge转换
layer.contents = (__bridge id)image.CGImage;
    
//2. imageView图片有contentMode 属性设置图片填充方式
layer.contentsGravity =    ;//不被拉伸
    
//3. maskToBounds 相当于 clipsToBounds 属性来设置边界
//默认情况下,UIView 和 CALayer 都会绘制走出边界的内容或子视图
    
//4. contentsRect 允许我们在图层边框里显示寄宿图的一个子域
//它使用单位坐标(0-1),是一个相对值,是相对于寄宿图的尺寸而言
//这个属性可以将加载的一张图片,切成多张图片
layer.contentsRect = CGRectMake(0.4, 0.2, 0.3, 0.3);
    
//5. UIView 有三个布局属性 frame,bounds,center
//CALayer 有三个布局属性 frame,bounds,position
//frame 是外部坐标,bounds 是内部坐标
//当操纵视图的 frame,实际上是在改变位于视图下方 CALayer 的 frame
//当视图旋转后,其frame 与 bounds 一般会不一致。因为frame 代表了覆盖在
//图层旋转后整个轴对齐的矩形区域。
    
//6. 锚点
//anchorPoint默认居中(0.5,0.5),可以理解为移动图层的把柄
//可以通过移动锚点来改变 frame,锚点改变后,其旋转中心点也改变
    
//7. conrnerRadius属性控制图层的曲率,只影响背景颜色而不影响子视图
//maskToBounds 设成 YES,才会有截取
    
//borderColor 设置边框颜色
//borderWidth 设置边框粗细
    
//8. shadowColor 阴影颜色
//shadowOffset 阴影方向及距离
//shadowRadius 阴影模糊度
//shadowPath 阴影路径
//注意:开启了masksToBounds 属性,越界全被截剪,阴影则无法显示
    
//9. mask 属性本身也是一个CALayer类型
//opacity 与 alpha 相似,都会影响子图层。
    
//10. 当有多个子视图时,由于透明度叠加造成效果很不理想。
//shouldRasterize 属性会将多个图层整合成整体图片然后设置透明度
//self.myLayer.shouldRasterize = YES;
    
    
//11. 变换
//UIView   transform 属性,CGAffineTransform 类型(二维坐标系)
//CALayer  transform 属性,CATransform3D 类型 (三维坐标第)
//         affineTransform 属性,CGAffineTransform类型
    
//layer.affineTransform = CGAffineTransformMakeRotation(M_PI/4);
    
//混合变换
/*
    CGAffineTransform transform = CGAffineTransformIdentity;//初始空值
    transform = CGAffineTransformScale(transform, 0.5, 0.5);
    transform = CGAffineTransformRotate(transform, M_PI/4);
    transform = CGAffineTransformTranslate(transform, 10, 30);
    layer.affineTransform = transform;
*/
//或者
//CGAffineTransformConcat(transform, transform);
    
//旋转
//基于最初的位置旋转
//self.myLayer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
//基于给定的transform 旋转
//self.myLayer.transform = CATransform3DRotate(self.myLayer.transform, M_PI, 0, 1, 0);

//**********透视效果,默认通过 m34 来改变*************
//CATransform3D transform = CATransform3DIdentity;
//transform.m34 = -1.0/500; //(500-1000是一个比较和适的值)
//transform = CATransform3DRotate(transform, M_PI_4, 1, 0, 0);
//layer.transform = transform;
    
//12. 背面,当视图旋转后背面不会被绘制
//self.myLayer.doubleSided = NO;

CATransition (过渡动画)

- (void)transitionAnimation{
    
    CATransition *transition = [CATransition animation];
    transition.fillMode = kCAFillModeForwards;
    transition.removedOnCompletion = YES;
    transition.startProgress = 0.0;
    transition.endProgress = 1.0;
    transition.duration = 1.0;
    transition.type = kCATransitionMoveIn;
    
    
    /*
     私有接口(慎用)
     cube   立体翻转
     oglFlip 翻转
     suckEffect 收缩效果
     rippleEffect 水滴波纹
     pageCurl   翻页
     pageUnCurl
     cameralIrisHollowOpen 摄像头打开效果
     cameraIrisHollowClose  关闭效果
     
     */
    
    /*
     公有接口
     kCATransitionFade 淡出效果
     kCATransitionMoveIn 新视图移到旧视图上
     kCATransitionPush  新视图推出旧视图
     kCATransitionReveal 移开旧视图显示新视图
     */
    
    transition.subtype = kCATransitionFromLeft;
    
    /*
     kCATransitionFromRight
     kCATransitionFromLeft
     kCATransitionFromTop
     kCATransitionFromBottom
     */
    
    
    [self.imageView.layer addAnimation:transition forKey:@"transition"];
    [self setNewImage];
}

只要用手势或计时器回调下面方法即可实现轮播效果

- (void)setNewImage{
    static int i = 5;
    i++;
    int imageIndex = i%5;
    NSString *imageName = [NSString stringWithFormat:@"%d.jpg",imageIndex];
    [self.imageView setImage:[UIImage imageNamed:imageName]];
}

或者

[UIView transitionWithView:_imageView
                      duration:1.0
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:^{
 // [self.imageView setFrame:CGRectMake(0, 0, 300, 300)];            
     [self setNewImage];
                    } completion:nil];

// 在window上执行CATransition, 即可在ViewController转场时执行动画。
[self.view.window.layer addAnimation:animation forKey:@"kTransitionAnimation"];
PresentedViewController *presentedVC = [[PresentedViewController alloc] init];
[self presentViewController:presentedVC animated:NO completion:nil];
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    UIViewController *viewController1 = [[FirstViewController alloc]initWithNibName:@"FirstViewController" bundle:nil];
    UIViewController *viewController2 = [[SecondViewController alloc]initWithNibName:@"SecondViewController" bundle:nil];
    
    viewController2.title = @"第一";
    viewController1.title = @"第二";
    self.tabBarController = [[UITabBarController alloc]init];
    self.tabBarController.viewControllers = @[viewController1,viewController2];
    self.tabBarController.delegate = self;
    self.window.rootViewController = self.tabBarController;
    [self.window makeKeyAndVisible];
    
    
    return YES;
}

-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionFade;
    transition.duration= 3; //3秒时间过渡效果会明显一些
    [self.tabBarController.view.layer addAnimation:transition forKey:@"transition"];
}

CAKeyframeAnimation

- (void)keyFrameAnimation{
    
      CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
      UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:self.view.center
                                                          radius:100
                                                      startAngle:0
                                                        endAngle:2 * M_PI
                                                       clockwise:YES];//顺时针方向
      keyframeAnimation.path = path.CGPath;//UIKit框架转CG框架
      keyframeAnimation.duration = 3;
      keyframeAnimation.repeatCount = 1;
      keyframeAnimation.fillMode = kCAFillModeForwards;
      keyframeAnimation.removedOnCompletion  = NO;
      keyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
      //这个属性很有意思。
      keyframeAnimation.rotationMode = KCAAnimationRotateAuto;
      //*******设置value后会覆盖path********//
      //KeyframeAnimation.values = @[ ];
      [self.layer addAnimation:keyframeAnimation forKey:@"keyframeAnimation"];
 }

- (void)addShakeAnimationForView:(UIView *)view withDuration:(NSTimeInterval)duration {
    
    CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
    CGFloat currentTx = view.transform.tx;
    
    animation.delegate = self;
    animation.duration = duration;
    animation.values = @[ @(currentTx), @(currentTx + 10), @(currentTx-8), @(currentTx + 8), @(currentTx -5), @(currentTx + 5), @(currentTx) ];
    animation.keyTimes = @[ @(0), @(0.225), @(0.425), @(0.6), @(0.75), @(0.875), @(1) ];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.layer addAnimation:animation forKey:@"keyframeAnimation"];
}

CABasicAnimation

/**
 *  CABsicAnimation 的实例对象只是一个数据模型,
 *  addAnimation:forKey只是将对象的copy,所以也可以添加到另外一个layer上
 *
 */

/**
 *  为什么动画会返回原状态
 *  添加动画时,真正移动的并不是视图本身,而是presentation Layer的一个缓存
 *  动画开始,presentation Layer开始移动,原始layer隐藏
 *  动画结束,presentation layer开始移除,原始layer显示
 */

- (void)basicAnimation{
    
    //旋转动画
    CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    rotateAnimation.duration = 3.0;
    rotateAnimation.repeatCount = 100;
    rotateAnimation.autoreverses = YES;
    rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
    rotateAnimation.toValue = [NSNumber numberWithFloat:6*M_PI];
    [self.layer addAnimation:rotateAnimation forKey:@"rotate"];
   
    //放大 缩小
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnimation.duration = 3.0;
    scaleAnimation.repeatCount = 1;
    scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleAnimation.toValue = [NSNumber numberWithFloat:3];
    //动画结束后保持移动后的位置
    scaleAnimation.removedOnCompletion = NO;
    scaleAnimation.fillMode = kCAFillModeForwards;
    //设置动画速率
    scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    /**
     *  kCAMediaTimingFunctionLinear
     *  kCAMediaTimingFunctionEaseIn  开始慢,后来快
     *  kCAMediaTimingFunctionEaseOut
     */
    
   [self.layer addAnimation:scaleAnimation forKey:@"scale"];
    //设置代理可以监测动画开始和结束时的动作
    scaleAnimation.delegate = self;
    
    
    //平移动画
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.duration = 3.0;
    animation.autoreverses = YES;
    animation.repeatCount = 100;
    animation.fromValue = [NSValue valueWithCGPoint:_layer.position];
    CGPoint toPoint = _layer.position;
    toPoint.x = toPoint.x+180;
    animation.toValue = [NSValue valueWithCGPoint:toPoint];
    [self.layer addAnimation:animation forKey:@"move"];
    
}

UIView动画

3D变换可将图层顺序更改
动画中更改使用transform可以快速方便地改变frame 
 [UIView animateWithDuration:0.5 animations:^{
        self.testView.layer.transform = CATransform3DMakeTranslation(10, 10, 1);
    } completion:nil];
[UIView animateWithDuration:0.5 animations:^{
        self.testView.transform = CGAffineTransformMakeTranslation(10, 10);
    } completion:nil];

-(void)normalAnimation{
    [UIView animateWithDuration:2
                          delay:1
                        options:UIViewAnimationOptionRepeat
                     animations:^{
                         [UIView setAnimationRepeatCount:3];
                         [UIView setAnimationRepeatAutoreverses:YES];
                         self.redView.center = self.view.center;
                     }
                     completion:^(BOOL finished){
                         NSLog(@"finished--%d",finished); }
     ];  
}

UIViewAnimationOptions op = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState;
[UIView animateWithDuration:0.1
                        delay:0 
                      options:op
                   animations:^{
            //view缩小
            [_view.layer setValue:@(0.5) forKeyPath:@"transform.scale"];
        } completion:^(BOOL finished) {
          
            [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
            // view放大
             [_view.layer setValue:@(1.08) forKeyPath:@"transform.scale"];
            } completion:^(BOOL finished) {
                       [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
                       //view恢得原样
                        [_view.layer setValue:@(1) forKeyPath:@"transform.scale"];
                } completion:NULL];
            }];
        }];
-(void)springAnimation{
    
    [UIView animateWithDuration:1
                          delay:0
         usingSpringWithDamping:100//类似弹簧振动效果,越小越明显
          initialSpringVelocity:10 //初始速度
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         [UIView setAnimationRepeatCount:5];
                         self.redView.frame = CGRectMake(50, 200, 100, 100);
                     }
                     completion:^(BOOL finished) {
                         
                     }];
}
-(void)keyFrameAnimationView{
    [UIView animateKeyframesWithDuration:6
                                   delay:0.0
                                 options:UIViewKeyframeAnimationOptionLayoutSubviews
                              animations:^{
                                  
                                  [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.3 animations:^{
                                      self.redView.center = self.view.center;
                                  }];
                                  [UIView addKeyframeWithRelativeStartTime:0.3 relativeDuration:0.3 animations:^{
                                      self.redView.backgroundColor = [UIColor orangeColor];
                                  }];
                                  [UIView addKeyframeWithRelativeStartTime:0.6 relativeDuration:0.4 animations:^{
                                      CGRect rect= self.redView.frame;
                                      rect.size.width +=rect.size.width;
                                      rect.size.height +=rect.size.height;
                                      self.redView.frame =rect;
                                  }];
                                  //relativeStartTime
                                  //relativeDuration  都是相对时间,占总时间的占比
                                  
                              } completion:^(BOOL finished) {
                                  NSLog(@"动画结束");
                              }];
}

UIView动画停止

- (void)startAnimation {
 [UIView animateWithDuration:1.0
                       delay:0.0
                     options:UIViewAnimationOptionCurveLinear |
                             UIViewAnimationOptionAllowUserInteraction
                  animations:^(void) {
                         //动画
                } completion:^(BOOL finished) {

       if(!self.canceled) {
        __weak id weakSelf = self;
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                     [weakSelf startAnimation];
                }];
         }
      }];
}
上一篇下一篇

猜你喜欢

热点阅读