动画基础

某种意义 上苹果已经提供了优美简洁的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 (过渡动画)

  • 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];

  • CATransition动画实现简单的转场效果
// 在window上执行CATransition, 即可在ViewController转场时执行动画。
[self.view.window.layer addAnimation:animation forKey:@"kTransitionAnimation"];
PresentedViewController *presentedVC = [[PresentedViewController alloc] init];
[self presentViewController:presentedVC animated:NO completion:nil];
  • tabBarViewController 可以添加过渡效果
-(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];
            }];
        }];
  • spring动画
-(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];
                }];
         }
      }];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容