iOS动画及开源库iOS效果iOS学习

核心动画 Core Animation(二、CAAnimatio

2017-08-22  本文已影响154人  寻形觅影

Core Animation 实际是直接作用在 CALayer 上的,而不是UIView上。view是负责响应事件的,layer是负责显示的,可以看成view是layer的包装类。同时Core Animation 的动画执行过程都是在后台操作的,不会阻塞主线程。
  CAAnimation是所有动画对象的父类,负责控制动画的持续时间和速度,是个 抽象类 ---- 即,不能直接使用,应该使用其具体子类。需要注意的是CAAnimation 和 CAPropertyAnimation 都是 抽象类

首先,我们先看一下继承结构图:

CAAnimation继承结构图

CAAnimation(动画基类)

CAAnimation主要包含三个属性,两个代理方法和遵循的CAMediaTiming协议。

1、属性:
2、代理方法:
3、CAMediaTiming协议

CAMediaTiming协议通过layer和animations实现,它对一个分层的定时系统进行建模,每个对象描述从对象的父对象到自己本身本地时间的时间值的映射(有点拗口~)。
 马赫时间被定义为转换为秒的绝对时间,系统提供了CACurrentMediaTime()函数来实现此功能,方便查询当前的绝对时间(即从设备启动后经历的时间的秒数,其实没有实际意义,可以用来测试代码效率,在这里作为参照时间使用,不需要管实际值是多少)。

该协议共包括8个属性:

以上属性均可组合使用,以达到理想的效果。关于以上属性间的关系可以参考一下下图(关系图),这里参考了 大卫·罗恩奎斯特 的 Controlling Animation Timing。这篇文章,在此表示非常的感谢!

关系图

一、CAPropertyAnimation (属性动画)

CAPropertyAnimation是基于属性的动画子类,它与CAAnimation一样是一个抽象类 --- 不能直接使用,应该使用其具体子类。共包含一个创建方法和四个属性:

+ (nullable instancetype)functionWithName:(NSString *)name;
@property(readonly) NSString *name;

其中参数name由系统提供:

CA_EXTERN NSString * const kCAValueFunctionRotateX
CA_EXTERN NSString * const kCAValueFunctionRotateY
CA_EXTERN NSString * const kCAValueFunctionRotateZ

CA_EXTERN NSString * const kCAValueFunctionScale
CA_EXTERN NSString * const kCAValueFunctionScaleX
CA_EXTERN NSString * const kCAValueFunctionScaleY
CA_EXTERN NSString * const kCAValueFunctionScaleZ

CA_EXTERN NSString * const kCAValueFunctionTranslate
CA_EXTERN NSString * const kCAValueFunctionTranslateX
CA_EXTERN NSString * const kCAValueFunctionTranslateY
CA_EXTERN NSString * const kCAValueFunctionTranslateZ
1、CABaseAnimation(基础动画)

CABaseAnimation用来实现一些比较简单的动画比如平移、缩放、旋转等,它本身只有三个属性,而且如果使用该动画,则至多有两个值不为nil。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CABasicAnimation * baseAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
    baseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    baseAnimation.duration = 5.0;

//    baseAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(300, 500)];
//    [self.redView.layer addAnimation:baseAnimation forKey:@"onlyFromValue"];
    
//    baseAnimation.byValue = [NSValue valueWithCGPoint:CGPointMake(300, 500)];
//    [self.redView.layer addAnimation:baseAnimation forKey:@"onlyByValue"];
    
//    baseAnimation.byValue = [NSValue valueWithCGPoint:CGPointMake(100, 175)];
//    baseAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 500)];
//    [self.redView.layer addAnimation:baseAnimation forKey:@"byValue-toValue"];
    
    baseAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(300, 200)];
    baseAnimation.byValue = [NSValue valueWithCGPoint:CGPointMake(100, 175)];
    baseAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 500)];
    [self.redView.layer addAnimation:baseAnimation forKey:@"fromValue-byValue-toValue"];
}
onlyFromValue效果图 onlyByValue效果图 byValue-toValue效果图
2、CAKeyFrameAnimation(关键帧动画)

 关键帧动画的值可以指定一个value数组或者一个路径(CGPathRef)。和CABasicAnimation动画相比,在同一时间内对同一layer可以做多种不同动画,并且可以控制各动画的执行节奏。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CAKeyframeAnimation * keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    keyFrameAni.duration = 10.0;
    keyFrameAni.values = @[[NSValue valueWithCGPoint:CGPointMake(50, 100)], [NSValue valueWithCGPoint:CGPointMake(300, 100)], [NSValue valueWithCGPoint:CGPointMake(300, 500)], [NSValue valueWithCGPoint:CGPointMake(50, 500)],[NSValue valueWithCGPoint:CGPointMake(50, 100)]];
    keyFrameAni.keyTimes = @[[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.3], [NSNumber numberWithFloat:0.5], [NSNumber numberWithFloat:0.8], [NSNumber numberWithFloat:1.0]];
    keyFrameAni.timingFunctions =@[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
    if (!isPath) {
        keyFrameAni.path = nil;
        keyFrameAni.rotationMode = nil;
        isPath = YES;
    }else{
        UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 100, 250, 400) byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(125, 125)];
        keyFrameAni.path = path.CGPath;
        keyFrameAni.calculationMode = kCAAnimationPaced;
        keyFrameAni.rotationMode = kCAAnimationRotateAuto;
//        keyFrameAni.rotationMode = kCAAnimationRotateAutoReverse;
        isPath = NO;
    }
    [self.imageView.layer addAnimation:keyFrameAni forKey:@"noPath"];
}

看一下简单的效果:

keyFrameAnimation效果图.gif
3、CASpringAnimation(弹性动画)

 弹性动画父类是CABasicAnimation,主要用来设置类似于缓冲、减速动画。

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.redView = [UIView new];
    self.redView.frame = CGRectMake(175, 175, 100, 100);
    self.redView.center = self.view.center;
    self.redView.backgroundColor = [UIColor redColor];
    self.redView.alpha = 0.5;
    [self.view addSubview:self.redView];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CASpringAnimation * springAni = [CASpringAnimation animationWithKeyPath:@"bounds.size"];
    springAni.toValue = [NSValue valueWithCGSize:CGSizeMake(250, 100)];
    springAni.mass = 5;
    springAni.stiffness = 500;
    springAni.damping = 15;
    springAni.initialVelocity = -10;
    springAni.duration = springAni.settlingDuration;
    [self.redView.layer addAnimation:springAni forKey:@"spring"];
}
springAnimation效果图.gif

二、CATransition(转场动画)

 主要用于从一个场景向另一个场景的动画过渡。

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    i = -1;
    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 275, 400)];
    self.imageView.image = [UIImage imageNamed:@"boy"];
    [self.view addSubview:self.imageView];
    self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 550, 275, 50)];
    self.nameLabel.backgroundColor = [UIColor redColor];
    self.nameLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:self.nameLabel];
    
    self.imageNames = @[@"boy", @"loli", @"romance", @"poem", @"effort"];
    self.animationTypes = @[kCATransitionFade, kCATransitionMoveIn, kCATransitionPush, kCATransitionReveal, @"cube", @"suckEffect", @"rippleEffect", @"pageCurl", @"pageUnCurl", @"oglFlip", @"cameraIrisHollowOpen", @"cameraIrisHollowClose"];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (i == self.animationTypes.count-1) {
        i = 0;
    }else{
        i = i+1;
    }
    CATransition * transition = [CATransition animation];
    transition.duration = 2.0;
    transition.type = self.animationTypes[i];
    transition.subtype = kCATransitionFromRight;
    self.imageView.image = [UIImage imageNamed:self.imageNames[i%5]];
    self.nameLabel.text = self.animationTypes[i];
    [self.imageView.layer addAnimation:transition forKey:@"transition"];
}
transition效果图

三、CAAnimationGroup(动画组)

 只有一个属性@property(nullable, copy) NSArray<CAAnimation *> *animations;一组CAAnimation对象。 数组的每个成员将使用正常规则在父动画的时间空间中同时运行(并发)。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CABasicAnimation * baseAni = [CABasicAnimation animationWithKeyPath:@"transform"];
    baseAni.duration = 5.0;
    CATransform3D transform = CATransform3DMakeRotation(M_PI, 100, 100, 0);
    baseAni.toValue =[NSValue valueWithCATransform3D:transform];
    
    CASpringAnimation * springAni = [CASpringAnimation animationWithKeyPath:@"bounds.size"];
    springAni.toValue = [NSValue valueWithCGSize:CGSizeMake(100, 220)];
    springAni.mass = 2;
    springAni.stiffness = 300;
    springAni.damping = 5;
    springAni.fillMode = kCAFillModeForwards;
    springAni.duration = springAni.settlingDuration;
    
    CAKeyframeAnimation * keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    keyFrameAni.duration = 5.0;
    UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 100, 250, 400) byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(125, 125)];
    keyFrameAni.path = path.CGPath;
    keyFrameAni.calculationMode = kCAAnimationPaced;
    keyFrameAni.rotationMode = kCAAnimationRotateAuto;
    
    CAAnimationGroup * groupAni = [CAAnimationGroup animation];
    groupAni.animations = @[baseAni, springAni, keyFrameAni];
    groupAni.duration = 5;
    [self.imageView.layer addAnimation:groupAni forKey:@"group"];
}
group效果图
上一篇 下一篇

猜你喜欢

热点阅读