iOS-核心动画(三)关键帧动画、动画组、转场动画

一、关键帧动画(CAKeyframeAnimation)

    CAKeyframeAnimation和CABaseAnimation都属于CAPropertyAnimatin的子类。CABaseAnimation只能从一个数值(fromValue)变换成另一个数值(toValue),而CAKeyframeAnimation则会使用一个NSArray保存一组关键帧。 
重要属性
  • values : 就是上述的NSArray对象。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
  • path : 可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的anchorPoint和position起作用。如果你设置了path,那么values将被忽略。
  • keyTimes : 可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的。
  • values:值的数组
  • path:值得路径
  • keyTimes:时间值(0,1)
    timingFunctions:速度控制的数组
  • calculationMode:动画样式
    • kCAAnimationLinear 自定义控制动画的时间(线性)可以设置keyTimes
    • kCAAnimationDiscrete 离散动画 没有任何补间动画 使用keytimes@[@0.3,@0.5,@1.0];
    • kCAAnimationPaced 节奏动画 自动计算动画的运动时间
    • kCAAnimationCubic 曲线动画 需要设置timingFunctions
    • kCAAnimationCubicPaced 节奏曲线动画 自动计算
  • rotationMode:旋转的样式
    • kCAAnimationRotateAuto 自动
    • kCAAnimationRotateAutoReverse 自动翻转
      第一种效果:
#import "ViewController.h"

@interface ViewController ()
//背景
@property (nonatomic, strong) CALayer *layer;
//花瓣
@property (nonatomic, strong) CALayer *petalLayer;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor blackColor];
    [self.view.layer addSublayer:self.layer];
    [self.view.layer addSublayer:self.petalLayer];

}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self demo2:[[touches anyObject]locationInView:self.view]];
}

- (void)demo2:(CGPoint)toPoint{
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:self.petalLayer.position];

    [path addCurveToPoint:toPoint controlPoint1:CGPointMake(100, 100) controlPoint2:CGPointMake(52, 600)];
    animation.path = path.CGPath;
    animation.duration = 3;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAScrollBoth;
    //    自动计算每个运动轨迹之间补间动画的时间
    animation.calculationMode = kCAAnimationCubicPaced;

    animation.rotationMode = kCAAnimationRotateAuto;

    [self.petalLayer addAnimation:animation forKey:@""];
}

- (CALayer *)petalLayer{
    if (_petalLayer) {
        return _petalLayer;
    }
    _petalLayer = [CALayer layer];
    _petalLayer.position = CGPointMake(self.view.center.x, 50);
    UIImage *image =[UIImage imageNamed:@"huaban-1"];
    _petalLayer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
    _petalLayer.contents = (id)image.CGImage;

    return _petalLayer;
}

- (CALayer *)layer{
    if (_layer) {
        return _layer;
    }
    _layer = [CALayer layer];
    _layer.position = CGPointMake(self.view.center.x, self.view.center.y+100);
    UIImage *image =[UIImage imageNamed:@"background"];
    _layer.bounds = CGRectMake(0, 0, image.size.width/2, image.size.height/2);
    _layer.contents = (id)image.CGImage;

    return _layer;

}

@end
效果图如下

关键帧动画1

第二种效果

//  关键帧动画NO.2

#import "PatingView.h"

@implementation PatingView

- (UIBezierPath *)path{
    if (_path!=nil) {
        return _path;
    }
    _path = [UIBezierPath bezierPath];
    return _path;
}

- (CALayer *)pointLayer{
    if (_pointLayer) {
        return _pointLayer;
    }
    _pointLayer = [CALayer layer];
    _pointLayer.frame = CGRectMake(0, -20, 15, 15);
    _pointLayer.cornerRadius = 15/2;
    _pointLayer.backgroundColor = [UIColor colorWithRed:0.917 green:0.5309 blue:1.0 alpha:1.0].CGColor;
    _pointLayer.shadowOpacity = 0.8;
    _pointLayer.shadowRadius = 3;
    _pointLayer.shadowColor = [UIColor colorWithRed:1.0 green:0.6648 blue:0.0006 alpha:1.0].CGColor;

    [self.layer addSublayer:_pointLayer];
    return _pointLayer;
}

/*
- (CALayer *)pointLayer{
    if (_pointLayer) {
        return _pointLayer;
    }
    CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
    replicatorLayer.frame = self.bounds;
    replicatorLayer.instanceCount = 30;
    replicatorLayer.instanceDelay = 0.5;
    replicatorLayer.backgroundColor = [UIColor clearColor].CGColor;
    [self.layer addSublayer:replicatorLayer];

    _pointLayer = [CALayer layer];
    _pointLayer.frame = CGRectMake(0, -20, 15, 15);
    _pointLayer.cornerRadius = 15/2;
    _pointLayer.backgroundColor = [UIColor colorWithRed:0.917 green:0.5309 blue:1.0 alpha:1.0].CGColor;
    _pointLayer.shadowOpacity = 0.8;
    _pointLayer.shadowRadius = 3;
    _pointLayer.shadowColor = [UIColor colorWithRed:1.0 green:0.6648 blue:0.0006 alpha:1.0].CGColor;

    [replicatorLayer addSublayer:_pointLayer];

    return _pointLayer;
}
*/
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.path moveToPoint:[[touches anyObject] locationInView:self]];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.path addLineToPoint:[[touches anyObject] locationInView:self]];

    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    [[UIColor colorWithRed:0.0444 green:0.4332 blue:1.0 alpha:1.0] set];
    self.path.lineWidth = 5;
    [self.path stroke];
}

- (void)start{
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.path = self.path.CGPath;
    animation.duration = 5;
    animation.repeatCount = HUGE;
    [self.pointLayer addAnimation:animation forKey:@"move"];

}

@end
效果图如下

关键帧效果图2

二、CAAnimationGroup 动画组,

动画组可以让动画同时执行且不相互影响,他有一个数组animations:动画的数组;动画组设置的持续时间会影响到动画组内部的动画持久时间动画组。
重要属性
  • animations:动画的数组
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blackColor];

    [self.view.layer addSublayer:self.layer];
    [self.view.layer addSublayer:self.petalLayer];
}

- (CALayer *)petalLayer{
    if (_petalLayer) {
        return _petalLayer;
    }
    _petalLayer = [CALayer layer];
    _petalLayer.position = CGPointMake(self.view.center.x, 50);
    UIImage *image =[UIImage imageNamed:@"huaban-1"];
    _petalLayer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
    _petalLayer.contents = (id)image.CGImage;

    return _petalLayer;
}

- (CALayer *)layer{
    if (_layer) {
        return _layer;
    }
    _layer = [CALayer layer];
    _layer.position = CGPointMake(self.view.center.x, self.view.center.y+100);
    UIImage *image =[UIImage imageNamed:@"background"];
    _layer.bounds = CGRectMake(0, 0, image.size.width/2, image.size.height/2);
    _layer.contents = (id)image.CGImage;

    return _layer;


}

- (void)animationGroup:(CGPoint)endPoint{
    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    animationGroup.animations = @[[self move:endPoint], [self moveToBig]];
    animationGroup.duration = 5;

    /*
        动画组中设置的时间控制类属性会影响到动画组中设置的时间控制类属性
        在动画组中统一设置媒体时间控制类属性,入股需要单独设置,动画组中必须未设置相关属性
     1.CAMediaTiming媒体时间类协议
     核心动画关于时间类的控制 是遵守了CAMediaTiming中的协议内容
     1.beginTime 动画开始的时间 默认为0
     2.duration 动画的持续时间 默认为0 持续时间 受速度的影响 实际的动画完成时间 = 持续时间/速度
     3.speed 动画播放的速度 默认为1 速度设置成0 可以暂停动画
     speed 2秒  duration 60秒 动画真正播放完成的时间 30秒
     4.timeOffset 动画播放时间的偏移量
     5.repeatCount 动画的循环次数 默认是0 只播放一次
     6.repeatDuration 动画循环的持续时间  只能设置其中的一个属性  repeatCount/repeatDuration
     7.autoreverses  是否以动画的形式 返回到播放之前的状态
     8.fillMode 设置当前对象在非活动时间段的状态
     要想fillMode有效 需设置removedOnCompletion = NO
     kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
     kCAFillModeBackwards 立即进入动画的初始状态并等待动画开始
     kCAFillModeBoth 动画加入后开始之前 layer处于动画初始状态 动画结束后layer保持动画最后的状态
     kCAFillModeRemoved 默认值 动画结束后 layer会恢复到之前的状态

     */
    animationGroup.removedOnCompletion = NO;
    animationGroup.fillMode = kCAFillModeBoth;

    [self.petalLayer addAnimation:animationGroup forKey:@""];
}

/**
 *  让图层移动的动画
 *
 *  @param endPoint 终点
 *
 *  @return 移动的动画
 */
- (CAKeyframeAnimation *)move:(CGPoint)endPoint{
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//    贝塞尔路径
    UIBezierPath *path = [UIBezierPath bezierPath];
//    设置起始点
    [path moveToPoint:self.petalLayer.position];
    /**
     *  画曲线
     *
     *  @param ToPoint 终点
     *
     *controlPoint1、controlPoint2 控制点
     */
    [path addCurveToPoint:endPoint controlPoint1:CGPointMake(50, 200) controlPoint2:CGPointMake(300, 400)];
    animation.path = path.CGPath;
//    kCAAnimationPaced 节奏动画(不是匀速)
//    kCAAnimationCubicPaced
    animation.calculationMode = kCAAnimationCubicPaced;

    return animation;
}

//放大
- (CABasicAnimation *)moveToBig{
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@""];

    animation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, CGRectGetWidth(self.petalLayer.bounds)*1.3, CGRectGetHeight(self.petalLayer.bounds)*1.3)];

    return  animation;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self animationGroup:[[touches anyObject]locationInView:self.view]];

}
@end

效果图如下
动画组动画效果

三、CATransition转场动画

属性

官方文档只提供了四种效果:

  • kCATransitionFade 交叉淡化过渡
  • kCATransitionMoveIn 新视图移到旧视图上面
  • kCATransitionPush 新视图把旧视图推出去
  • kCATransitionReveal 将旧视图移开,显示下面的新视图
私有api
  • pageCurl 向上翻一页
  • pageUnCurl 向下翻一页
  • rippleEffect 滴水效果
  • suckEffect 收缩效果 如一块布被抽走
  • cube 立方体效果
  • oglFlip 上下翻转效果
  • startProgress 开始的进度(0-1)(从那个开始)
  • endProgress 结束的进度(0-1)

    注意:私有api,不建议开发者们使用。因为苹果公司不提供维护,并且有可能造成你的app审核不通过
    示例

#import "ViewController.h"
#import "NextViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad]; 
}
- (IBAction)next:(id)sender {
    UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    NextViewController *nextVC = [storyBoard instantiateViewControllerWithIdentifier:@"NextViewController"];

    CATransition *animation = [CATransition animation];
    animation.type = @"rippleEffect";
    animation.duration = 3;
    [self.navigationController.view.layer addAnimation:animation forKey:@""];

    [self.navigationController pushViewController:nextVC animated:YES];
}

@end

NextViewController.m#import "NextViewController.h"

@interface NextViewController ()

@end

@implementation NextViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    CATransition *animation = [CATransition animation];
    animation.type = kCATransitionFade;
    animation.subtype = kCATransitionFromLeft;
    animation.duration = 3;

    [self.navigationController.view.layer addAnimation:animation forKey:@""];

    [self.navigationController popViewControllerAnimated:NO];
}

其实,任何复杂的动画其实都是由一个个简单的动画组装而成的,只要我们善于分解和组装,我们就能实现出满意的效果。动画其实也不是那么难。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值