首页 > 代码库 > iOS 动画基础-显式动画

iOS 动画基础-显式动画

摘要

显式动画

    属性动画

CABasicAnimation *animation = [CABasicAnimation animation];        [self updateHandsAnimated:NO];        animation.keyPath = @"transform";        animation.toValue = [NSValue valueWithCATransform3D:transform];        animation.duration = 0.5;        animation.delegate = self;        [animation setValue:handView forKey:@"handView"];

    关键帧动画

    CAKeyframeAnimation是另一种UIKit没有暴露出来但功能强大的类。和CABasicAnimation类似,CAKeyframeAnimation同样是CAPropertyAnimation的一个子类,它依然作用于单一的一个属性,但是和CABasicAnimation不一样的是,它不限制于设置一个起始和结束的值,而是可以根据一连串随意的值来做动画。

    关键帧起源于传动动画,意思是指主导的动画在显著改变发生时重绘当前帧(也就是关键帧),每帧之间剩下的绘制(可以通过关键帧推算出)将由熟练的艺术家来完成。CAKeyframeAnimation也是同样的道理:你提供了显著的帧,然后Core Animation在每帧之间进行插入。

- (IBAction)changeColor{    //create a keyframe animation    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];    animation.keyPath = @"backgroundColor";    animation.duration = 2.0;    animation.values = @[                         (__bridge id)[UIColor blueColor].CGColor,                         (__bridge id)[UIColor redColor].CGColor,                         (__bridge id)[UIColor greenColor].CGColor,                         (__bridge id)[UIColor blueColor].CGColor ];    //apply animation to layer    [self.colorLayer addAnimation:animation forKey:nil];}

    动画组

    CABasicAnimation和CAKeyframeAnimation仅仅作用于单独的属性,而CAAnimationGroup可以把这些动画组合在一起。CAAnimationGroup是另一个继承于CAAnimation的子类,它添加了一个animations数组的属性,用来组合别的动画。

    

- (void)viewDidLoad{    [super viewDidLoad];    //create a path    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];    [bezierPath moveToPoint:CGPointMake(0, 150)];    [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];    //draw the path using a CAShapeLayer    CAShapeLayer *pathLayer = [CAShapeLayer layer];    pathLayer.path = bezierPath.CGPath;    pathLayer.fillColor = [UIColor clearColor].CGColor;    pathLayer.strokeColor = [UIColor redColor].CGColor;    pathLayer.lineWidth = 3.0f;    [self.containerView.layer addSublayer:pathLayer];    //add a colored layer    CALayer *colorLayer = [CALayer layer];    colorLayer.frame = CGRectMake(0, 0, 64, 64);    colorLayer.position = CGPointMake(0, 150);    colorLayer.backgroundColor = [UIColor greenColor].CGColor;    [self.containerView.layer addSublayer:colorLayer];    //create the position animation    CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];    animation1.keyPath = @"position";    animation1.path = bezierPath.CGPath;    animation1.rotationMode = kCAAnimationRotateAuto;    //create the color animation    CABasicAnimation *animation2 = [CABasicAnimation animation];    animation2.keyPath = @"backgroundColor";    animation2.toValue = (__bridge id)[UIColor redColor].CGColor;    //create group animation    CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];    groupAnimation.animations = @[animation1, animation2];     groupAnimation.duration = 4.0;    //add the animation to the color layer    [colorLayer addAnimation:groupAnimation forKey:nil];}

    

    过渡

    有时候对于iOS应用程序来说,希望能通过属性动画来对比较难做动画的布局进行一些改变。比如交换一段文本和图片,或者用一段网格视图来替换,等等。属性动画只对图层的可动画属性起作用,所以如果要改变一个不能动画的属性(比如图片),或者从层级关系中添加或者移除图层,属性动画将不起作用。

    于是就有了过渡的概念。过渡并不像属性动画那样平滑地在两个值之间做动画,而是影响到整个图层的变化。过渡动画首    先展示之前的图层外观,然后通过一个交换过渡到新的外观。

    为了创建一个过渡动画,我们将使用CATransition,同样是另一个CAAnimation的子类,和别的子类不同,CATransition有一个type和subtype来标识变换效果。type属性是一个NSString类型,可以被设置成如下类型:

kCATransitionFade kCATransitionMoveIn kCATransitionPush kCATransitionReveal

到目前为止你只能使用上述四种类型,但你可以通过一些别的方法来自定义过渡效果,默认的过渡类型是kCATransitionFade,当你在改变图层属性之后,就创建了一个平滑的淡入淡出效果。kCATransitionPush,它创建了一个新的图层,从边缘的一侧滑动进来,把旧图层从另一侧推出去的效果。

kCATransitionMoveIn和kCATransitionReveal与kCATransitionPush类似,都实现了一个定向滑动的动画,但是有一些细微的不同,kCATransitionMoveIn从顶部滑动进入,但不像推送动画那样把老土层推走,然而kCATransitionReveal把原始的图层滑动出去来显示新的外观,而不是把新的图层滑动进入。

后面三种过渡类型都有一个默认的动画方向,它们都从左侧滑入,但是你可以通过subtype来控制它们的方向,提供了如下四种类型:

kCATransitionFromRight 

kCATransitionFromLeft 

kCATransitionFromTop 

kCATransitionFromBottom

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIImageView *imageView;@property (nonatomic, copy) NSArray *images;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    //set up images    self.images = @[[UIImage imageNamed:@"Anchor.png"],                    [UIImage imageNamed:@"Cone.png"],                    [UIImage imageNamed:@"Igloo.png"],                    [UIImage imageNamed:@"Spaceship.png"]];}- (IBAction)switchImage{    //set up crossfade transition    CATransition *transition = [CATransition animation];    transition.type = kCATransitionFade;    //apply transition to imageview backing layer    [self.imageView.layer addAnimation:transition forKey:nil];    //cycle to next image    UIImage *currentImage = self.imageView.image;    NSUInteger index = [self.images indexOfObject:currentImage];    index = (index + 1) % [self.images count];    self.imageView.image = self.images[index];}@end

    你可以从代码中看出,过渡动画和之前的属性动画或者动画组添加到图层上的方式一致,都是通过-addAnimation:forKey:方法。但是和属性动画不同的是,对指定的图层一次只能使用一次CATransition,因此,无论你对动画的键设置什么值,过渡动画都会对它的键设置成“transition”,也就是常量kCATransition。

    自定义动画

苹果通过UIView +transitionFromView:toView:duration:options:completion:和+transitionWithView:duration:options:animations:方法提供了Core Animation的过渡特性。但是这里的可用的过渡选项和CATransition的type属性提供的常量完全不同。UIView过渡方法中options参数可以由如下常量指定:

UIViewAnimationOptionTransitionFlipFromLeft 

 

    使用UIKit提供的方法来做过渡动画

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIImageView *imageView;@property (nonatomic, copy) NSArray *images;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad]; //set up images    self.images = @[[UIImage imageNamed:@"Anchor.png"],                    [UIImage imageNamed:@"Cone.png"],                    [UIImage imageNamed:@"Igloo.png"],                    [UIImage imageNamed:@"Spaceship.png"]];- (IBAction)switchImage{    [UIView transitionWithView:self.imageView duration:1.0                       options:UIViewAnimationOptionTransitionFlipFromLeft                    animations:^{                        //cycle to next image                        UIImage *currentImage = self.imageView.image;                        NSUInteger index = [self.images indexOfObject:currentImage];                        index = (index + 1) % [self.images count];                        self.imageView.image = self.images[index];                    }                    completion:NULL];}@end

 

iOS 动画基础-显式动画