IOS动画片机制

IOS动画机制

原文参考:http://www.cnblogs.com/kenshincui/p/3972100.html#uiviewanimation

coreAnimation官方资料翻译: http://www.cnblogs.com/pengyingh/articles/2396032.html

CAAnimation和CATransition

CATransfrom3D

IOS动画中的枚举UIViewAnimationOptions

粒子动画 CAEmitterLayer和CAEmitterCell

概览

在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画、关键帧动画、动画组、转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等。在今天的文章里您可以看到动画操作在iOS中是如何简单和高效,很多原来想做但是苦于没有思路的动画在iOS中将变得越发简单:

  1. CALayer
    1. CALayer简介 
    2. CALayer常用属性 
    3. CALayer绘图 
  2. Core Animation
    1. 基础动画 
    2. 关键帧动画 
    3. 动画组 
    4. 转场动画 
    5. 逐帧动画 
  3. UIView动画封装
    1. 基础动画 
    2. 关键帧动画 
    3. 转场动画
IOS动画片机制

CALayer

    在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮,一个文本标签,一个文本输入框,一个图标等等,这些都是UIView.

    UIView之所以能显示在屏幕上,完全是因为它内部的一个图层.

UIView的显示原理

    在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个图层.

?
1
@property(nonatomic,readonly,retain) CALayer *layer;

    当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有的内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了UIView的显示.

    换句话说,UIView本身不具备显示的功能,是它内部的层才有显示功能.

CALayer的基本使用

    通过操作CALayer对象,可以很方便的调整UIView的一些外观属性,比如阴影, 圆角大小, 边框宽度和颜色等.还可以给图层添加动画来实现一些比较炫酷的效果.

CALayer的属性

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 // 宽度和高度 
@property CGRect bounds;
 // 位置(默认指中点,具体由anchorPoint决定) 
@property CGPoint position;
 // 锚点(x,y的范围都是0-1),决定了position的含义 
@property CGPoint anchorPoint;
 // 背景颜色(CGColorRef类型) 
@property CGColorRef backgroundColor;
 // 形变属性 
@property CATransform3D transform;
 // 边框颜色(CGColorRef类型) 
@property CGColorRef borderColor;
 // 边框宽度 
@property CGFloat borderWidth;
 // 圆角半径
@property CGColorRef borderColor;
 //内容(比如设置为图片CGImageRef) 
@property(retain) id contents;

关于CALayer

    首先:

    CALayer 是定义在 QuartzCore 框架中的;

    CGImageRef, CGColorRe f两种数据类型是定义在在 CoreGraphics 框架中的;

    UIColor, UIImage 是定义在 UIKit 框架中.

    其次:

    QuartzCore 和 CoreGraphics 框架是可以跨平台使用的,在iOS和Mac OS X上都能使用 ;

    UIKit只能使用在iOS中.

    为了保证可移植性,QuartzCore不能使用UIImage, UIColor,只能使用CGImageRef, CGColorRef.

UIView和CALayer的选择

    通过CALayer, 就能做出跟UIImageView一样的界面效果. 既然CALayer和UIView都能实现相同的显示效果,那究竟该选择谁好呢?

    对比CALayer, UIView多了一个事件处理功能. 也就是说,CALayer不能处理用户的触摸事件,而UIView可以.

    所以,如果显示出来的东西需要跟用户进行交互的话, 用UIView; 如果不需要跟用户进行交互, 用UIView或者CALayer都可以;当然,CALayer的性能更高一些, 因为它少了事件处理功能, 更加轻量级.

position和anchorPoint

    CALayer有两个非常重要的属性:position和anchorPoint .

?
1
@property CGPoint position;

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

?
1
@property CGPoint anchorPoint;

    anchorPoint称为:"定位点" 或 "锚点";

    决定了CALayer身上的哪个点会在position属性所指的位置,以自己的左上角为原点(0,0);

    anchorPoint的 x ,y 的取值范围都是 0 ~ 1, 默认值为(0.5 ,0.5).

隐式动画

    每一个UIView内部都默认关联一个CALayer, 我们可以称这个layer为Root Layer(根层).

    所有的非Root Layer,也就是手动创建的CALayer对象,都存在着隐式动画.

什么是隐式动画 ?

    当对非Root Layer的部分属性进行修改时, 默认会自动产生一些动画效果.而这些属性称为Animatable Properties(可动画属性).

列举几个常见的Animatable Properties(可动画属性);

    bounds : 用于设置CALayer的宽度和高度 ; 修改这个值, 会产生缩放动画 .

    backgroundColor : 用于设置CALayer的背景色 ;修改这个属性会产生背景色的渐变动画 .

    position : 用于设置CALayer的位置 ;修改这个属性会产生平移动画 .

可以通过动画事务(CATransaction)关闭默认的隐式动画效果;

?
1
2
3
4
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.myview.layer.position = CGPointMake(10, 10);
[CATransaction commit];

CATransion应用举例

  1. - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        _parentView=[[UIView alloc]initWithFrame:CGRectMake(40, 40, 160, 240)];
        
        _parentView.backgroundColor=[UIColor blueColor];
        
        _imageView01=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 160, 240)];
        
        _imageView01.image=[UIImage imageNamed:@"17_1.jpg"];
        
        _imageView02=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 160, 240)];
        
        _imageView02.image=[UIImage imageNamed:@"17_2.jpg"];
        
        [_parentView addSubview:_imageView01];
        [_parentView addSubview:_imageView02];
        
        [self.view addSubview:_parentView];
        UIBarButtonItem *btnNext=[[UIBarButtonItem alloc]initWithTitle:@"下一级" style:UIBarButtonItemStyleBordered target:self action:@selector(pressNxet)];
        
        self.navigationItem.rightBarButtonItem=btnNext;
    }
    
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        CATransition *tranAnim=[[CATransition alloc]init];
        
        tranAnim.duration=2.0f;
        
        //"cube", suckEffect, oglFlip, rippleEffect, pageCurl, pageUnCurl, cameraIrisHollowOpen, cameraIrisHollowClose
    
        //设置动画类型,淡出动画
        tranAnim.type=@"cameraIrisHollowClose";
        //设置动画子类型出现的位置,从左侧出现
       // kCATransitionFromLeft
       // kCATransitionFromRight
       // kCATransitionFromTop
        //kCATransitionFromBottom
        
        tranAnim.subtype=kCATransitionFromBottom;
        //设置动画代理
        tranAnim.delegate=nil;
        
        //将动画添加到父视图的层中
        [_parentView.layer addAnimation:tranAnim forKey:@"anim"];
        
        //获得子时图一二的索引
        NSInteger index01=[_parentView.subviews indexOfObject:_imageView01];
        NSInteger index02=[_parentView.subviews indexOfObject:_imageView02];
        
        //交换两个子时图的索引的位置
        [_parentView exchangeSubviewAtIndex:index01 withSubviewAtIndex:index02];
    }
    
    -(void)pressNxet
    {
          //"cube", suckEffect, oglFlip, rippleEffect, pageCurl, pageUnCurl, cameraIrisHollowOpen, cameraIrisHollowClose
        CATransition*tranAnim=[CATransition animation];
        tranAnim.duration=1.0f;
        tranAnim.type=kCATransitionMoveIn;
        
        [self.navigationController.view.layer addAnimation:tranAnim forKey:@"ripplecuEffect"];
        tranAnim.subtype=kCATransitionFromLeft;
        VCSecond*second=[[VCSecond alloc]init];
        
        [self.navigationController pushViewController:second animated:YES];
    }
    
    CATransition *animation = [CATransition animation];
    animation.duration = 0.3;
    animation.type = @"cube";
    animation.subtype = kCATransitionFromLeft;
    
    //animation.type = kCATransitionFade;
    [[self.tableView layer] addAnimation:animation forKey:@"myAnimation"];

参数说明:
setType:可以返回四种类型:
kCATransitionFade淡出
kCATransitionFade淡出
kCATransitionMoveIn覆盖原图
kCATransitionPush推出
kCATransitionReveal底部显出来
setSubtype:也可以有四种类型:
kCATransitionFromRight;
kCATransitionFromLeft(默认值)
kCATransitionFromTop;
kCATransitionFromBottom

[animation setType:@"suckEffect"];
 
这里的suckEffect就是效果名称,可以用的效果主要有:
pageCurl   向上翻一页
pageUnCurl 向下翻一页
rippleEffect 滴水效果
suckEffect 收缩效果,如一块布被抽走
cube 立方体效果
oglFlip 上下翻转效果

animation.fillMode = kCAFillModeBackwards;
animation.startProgress = 0.01;
animation.endProgress = 0.99;

使用过渡动画,实现在同一个view上,左推,右推等各种动画,节省一个view;

IOS利用UIView的动画实现视图翻转效果
- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIBarButtonItem *flipButton=[[UIBarButtonItem alloc] 
                                 initWithTitle:@"翻转" 
                                 style:UIBarButtonItemStyleBordered 
                                 target:self 
                                 action:@selector(flip:)];
    self.navigationItem.rightBarButtonItem=flipButton;
    
    
    fistView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    fistView.tag=100;
    fistView.backgroundColor=[UIColor redColor];
    [self.view addSubview:fistView];
    
    secondView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    secondView.tag=101;
    secondView.backgroundColor=[UIColor yellowColor];
    [self.view addSubview:secondView];
}

-(void)flip:(id)sender{
    CGContextRef context=UIGraphicsGetCurrentContext();
    [UIView beginAnimations:nil context:context];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
    

   //这里时查找视图里的子视图(这种情况查找,可能时因为父视图里面不只两个视图)
    NSInteger fist= [[self.view subviews] indexOfObject:[self.view viewWithTag:100]];
    NSInteger seconde= [[self.view subviews] indexOfObject:[self.view viewWithTag:101]];
    
    [self.view exchangeSubviewAtIndex:fist withSubviewAtIndex:seconde];

   //当父视图里面只有两个视图的时候,可以直接使用下面这段.

    //[self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    [UIView setAnimationDelegate:self];
    [UIView commitAnimations];
}

  1. UIViw动画举例
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        self.window.backgroundColor = [UIColor whiteColor];
        
        _mViewAnim=[[UIView alloc]init];
        _mViewAnim.frame=CGRectMake(0, 0, 60, 60);
        _mViewAnim.backgroundColor=[UIColor redColor];
        
        [self.window addSubview:_mViewAnim];
        
        
        [self.window makeKeyAndVisible];
        return YES;
    }
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        static BOOL isFirst=YES;
        if (isFirst==YES)
        {
            //设置开始时的透明度,位置,透明度
    
            _mViewAnim.frame=CGRectMake(0, 0, 60, 60);
                   _mViewAnim.alpha=1.0f;
            _mViewAnim.backgroundColor=[UIColor blueColor];
            [UIView beginAnimations:@"anim01" context:nil];
            //动画时间
            [UIView setAnimationDuration:4.0f];
            //延时启动
            [UIView setAnimationDelay:0.0f];
            //设置动画结束后的代理对象
            [UIView setAnimationDelegate:self];
            //设置动画结束事件函数
            [UIView setAnimationDidStopSelector:@selector(animStop)];
            
            //设置动画的结束位置,透明度
            _mViewAnim.frame=CGRectMake(220, 0, 100, 100);
            _mViewAnim.backgroundColor=[UIColor grayColor];
            _mViewAnim.alpha=1.0f;
            
            //提交动画
            //[UIView commitAnimations];
            
            isFirst=NO;
            
        }
        else
        {
             [UIView beginAnimations:@"anim01" context:nil] ;
             [UIView setAnimationDuration:2.0f];
            //设置动画结束后的代理对象
            [UIView setAnimationDelegate:self];
            //设置动画结束事件函数
            [UIView setAnimationDidStopSelector:@selector(animStop)];
            
            //设置动画的结束位置,透明度
            _mViewAnim.frame=CGRectMake(220, 0, 100, 100);
            _mViewAnim.backgroundColor=[UIColor grayColor];
            _mViewAnim.alpha=1.0f;
        }
    
    }
    -(void)animStop
    {
        
        [UIView beginAnimations:@"anim01" context:nil] ;
        [UIView setAnimationDuration:5.0f];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(animStop1)];
        _mViewAnim.frame = CGRectMake(220, 380, 100, 100);
        _mViewAnim.backgroundColor = [UIColor blueColor];
    
    }
    -(void)animStop1
    {
        [UIView beginAnimations:@"anim01" context:nil] ;
        [UIView setAnimationDuration:5.0f];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(animStop2)];
        _mViewAnim.frame = CGRectMake(0, 380, 100, 100);
        _mViewAnim.backgroundColor = [UIColor blackColor];
    
        
    
    }
    -(void)animStop2
    {
        [UIView beginAnimations:@"anim01" context:nil] ;
        [UIView setAnimationDuration:5.0f];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(animStop3)];
        _mViewAnim.frame = CGRectMake(0, 0, 100, 100);
        _mViewAnim.backgroundColor = [UIColor yellowColor];
    }
    -(void)animStop3
    {
      //NSLog(@"动画结束");
        [UIView setAnimationDidStopSelector:@selector(touchesBegan:withEvent:)];
        [UIView commitAnimations];
    }
    

    UIView动画
    //初始化游戏场景
    -(void) startGame
    {
        NSMutableArray* _arrayNum =[[NSMutableArray alloc] init] ;
        
        for (int i = 0; i < 18; i++)
        {
            int random = arc4random() % 7 + 1 ;
            
            NSNumber* num = [NSNumber numberWithInt:random] ;
            [_arrayNum addObject:num] ;
            [_arrayNum addObject:num] ;
        }
        
        for (int i = 0 ; i < 6; i++)
        {
            for (int j = 0 ; j < 6; j++)
            {
                //创建按钮,宝石按钮
                UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom] ;
                
                btn.frame=CGRectMake(0,0,0,0);
                [UIView beginAnimations:@"开始" context:nil];
                [UIView setAnimationDuration:1.0f];
                [UIView setAnimationDelay:1.0f];
                [UIView setAnimationDelegate:self];
                
                btn.frame = CGRectMake(10+50*j, 40+50*i, 50, 50);
                [UIView commitAnimations];
                
                int r2 = arc4random() % _arrayNum.count ;
                
                int random = [[_arrayNum objectAtIndex:r2] intValue] ;
                
                [_arrayNum removeObjectAtIndex:r2] ;
                
                
                //1~7的随机数
               //int random = arc4random() % 7 + 1 ;
                //生成图像名字
                NSString* strName = [NSString stringWithFormat:@"%d.png",random] ;
                //读取图片对象
                UIImage* image = [UIImage imageNamed:strName];
                
                [btn setImage:image forState:UIControlStateNormal];
                
                btn.tag = random ;
                
                [btn addTarget:self action:@selector(pressBtn:) forControlEvents:UIControlEventTouchUpInside];
                
                [self.window addSubview:btn];
            }
        }
    }
    
    -(void) pressBtn:(UIButton*) btn
    {
        //是否为按下第一个图片
        //static BOOL isFirstPress = YES ;
        //记录按下的第一个按钮的对象
        static UIButton* btnFirst = nil ;
        
        //按下第一个宝石
        if (btnFirst == nil)
        {
            btnFirst = btn ;
            //取消按钮的交互
            btnFirst.enabled = NO ;
        }
        //按下第二个宝石
        else
        {
            //如果是同样的宝石
            if (btnFirst.tag == btn.tag)
            {
                //隐藏按钮
                btnFirst.hidden = YES ;
                btn.hidden = YES ;
                //btn.hidden = NO ;
            }
            else
            {
                //开启交互
                btnFirst.enabled = YES ;
            }
            //清空第一个宝石
            btnFirst = nil ;
        }
        
    }
    


    1. x轴缩放:
      CABasicAnimation *theAnimation;
      theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
      theAnimation.duration=8;
      theAnimation.removedOnCompletion = YES;
      theAnimation.fromValue = [NSNumber numberWithFloat:1];
      theAnimation.toValue = [NSNumber numberWithFloat:0.5];
       [yourView.layer addAnimation:theAnimation forKey:@"animateTransform"];

      y轴缩放:
      CABasicAnimation *theAnimation;
      theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
      theAnimation.duration=8;
      theAnimation.removedOnCompletion = YES;
      theAnimation.fromValue = [NSNumber numberWithFloat:1];
      theAnimation.toValue = [NSNumber numberWithFloat:0.5];
       [yourView.layer addAnimation:theAnimation forKey:@"animateTransform"];

      x轴,y轴同时按比例缩放:
      CABasicAnimation *theAnimation;
      theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
      theAnimation.duration=8;
      theAnimation.removedOnCompletion = YES;
      theAnimation.fromValue = [NSNumber numberWithFloat:1];
      theAnimation.toValue = [NSNumber numberWithFloat:0.5];
       [yourView.layer addAnimation:theAnimation forKey:@"animateTransform"];

      以上缩放是以view的中心点为中心缩放的,如果需要自定义缩放点,可以设置卯点:
      //中心点
      [yourView.layer setAnchorPoint:CGPointMake(0.5, 0.5)];

      //左上角
      [yourView.layer setAnchorPoint:CGPointMake(0, 0)];

      //右下角
      [yourView.layer setAnchorPoint:CGPointMake(1, 1)];