IOS动画机制

来源:互联网 发布:淘宝店修改店名要多久 编辑:程序博客网 时间:2024/05/01 21:41

原文参考: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复杂动画之抽丝剥茧(Objective-C & Swift)


概览

在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. 转场动画

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

绕Y轴旋转360度的做法,方法:给关键帧设置values,然后更新图片
/** @implementation UIView (i7Rotate360)  - (void)rotate360WithDuration:(CGFloat)aDuration repeatCount:(CGFloat)aRepeatCount timingMode:(enum i7Rotate360TimingMode)aMode {CAKeyframeAnimation *theAnimation = [CAKeyframeAnimation animation];theAnimation.values = [NSArray arrayWithObjects: [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0, 0,1,0)], [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.14, 0,1,0)], [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.14, 0,1,0)], [NSValue valueWithCATransform3D:CATransform3DMakeRotation(6.28, 0,1,0)], nil];theAnimation.cumulative = YES;theAnimation.duration = aDuration;theAnimation.repeatCount = aRepeatCount;theAnimation.removedOnCompletion = YES;if(aMode == i7Rotate360TimingModeEaseInEaseOut) { theAnimation.timingFunctions = [NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],  [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], nil ];}[self.layer addAnimation:theAnimation forKey:@"transform"]; }  - (void)rotate360WithDuration:(CGFloat)aDuration timingMode:(enum i7Rotate360TimingMode)aMode {[self rotate360WithDuration:aDuration repeatCount:1 timingMode:aMode]; }  - (void)rotate360WithDuration:(CGFloat)aDuration {[self rotate360WithDuration:aDuration repeatCount:1 timingMode:i7Rotate360TimingModeEaseInEaseOut]; } */@implementation HeadPhotoRotationViewController- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];    if (self) {        self.view. backgroundColor = [UIColor grayColor];    }    return self;}- (void)viewDidLoad{    [super viewDidLoad];    // 头像    _headImageView = [[UIImageView alloc] init];    _headImageView.backgroundColor = [UIColor clearColor];    _headImageView.frame = CGRectMake(100, 300, 100, 100);    _headImageView.layer.cornerRadius = 50.0;    _headImageView.layer.borderWidth = 1.0;    _headImageView.layer.borderColor = [UIColor whiteColor].CGColor;    _headImageView.layer.masksToBounds = YES;    _headImageView.image = [UIImage imageNamed:@"head1.jpg"];    [self.view addSubview:_headImageView];    UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];    btn.frame = CGRectMake(100, 100, 100, 100);    [btn setTitle:@"点击旋转" forState:UIControlStateNormal];    [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];    [self.view addSubview:btn];        [btn addTarget:self action:@selector(actionRotation:) forControlEvents:UIControlEventTouchUpInside];}- (void)actionRotation:(UIButton *)button{    [self performSelector:@selector(headPhotoAnimation) withObject:nil afterDelay:0.7];}- (void)headPhotoAnimation{    [_headImageView rotate360WithDuration:2.0 repeatCount:1 timingMode:i7Rotate360TimingModeLinear];    _headImageView.animationDuration = 2.0;    _headImageView.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:@"head1.jpg"],                                      [UIImage imageNamed:@"head2.jpg"],[UIImage imageNamed:@"head2.jpg"],                                      [UIImage imageNamed:@"head2.jpg"],[UIImage imageNamed:@"head2.jpg"],                                      [UIImage imageNamed:@"head1.jpg"], nil];    _headImageView.animationRepeatCount = 1;    [_headImageView startAnimating];}



0 0
原创粉丝点击