iOS中的核心动画

2017-05-18  本文已影响0人  小白文_Vincent
@property(nonatomic,readonly,retain)CALayer*layer; 

<h5>CALayer的基本使用</h5>

<b>UIView的Layer</b>

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // 设置阴影的颜色
    self.colorV.layer.shadowColor = [UIColor blackColor].CGColor;
    // 设置阴影的不透明度
    self.colorV.layer.shadowOpacity = 1;
    // 设置阴影的偏移量
    self.colorV.layer.shadowOffset = CGSizeMake(30, 30);
    // 设置阴影的模糊半径
    self.colorV.layer.shadowRadius = 10;
    
    // 边框宽度,往里面走的
    self.colorV.layer.borderWidth = 10;
    // 边框颜色,
    self.colorV.layer.borderColor = [UIColor brownColor].CGColor;
    
    // 设置圆角
    self.colorV.layer.cornerRadius = 30;
}

最终呈现效果


UIViewCALayer基本使用演示.gif

<b>UIView的Layer</b>

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

    // 设置阴影的颜色
    self.imageV.layer.shadowColor = [UIColor blackColor].CGColor;
    // 设置阴影的不透明度
    self.imageV.layer.shadowOpacity = 1;
    // 设置阴影的偏移量
    self.imageV.layer.shadowOffset = CGSizeMake(30, 30);
    // 设置阴影的模糊半径
    self.imageV.layer.shadowRadius = 10;
    
    // 边框宽度,往里面走的
    self.imageV.layer.borderWidth = 10;
    // 边框颜色,
    self.imageV.layer.borderColor = [UIColor brownColor].CGColor;

    // 注意:UIImageView的layer使用有些不一样,在设置圆角的时候需要注意:
    // 设置圆角
    self.imageV.layer.cornerRadius = 100;
}

呈现效果:


UIImage的CALayer基本使用演示1.gif

<b>原因:CALayer层中,有一个专门存放图片的层:contents</b>

    self.imageV.layer.masksToBounds = YES;

呈现效果:


UIImage的CALayer基本使用演示2.gif

<h5>CATransform3D</h5>

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

    // 3D效果
    [UIView animateWithDuration:0.5 animations:^{

        // 第一种设置方法:
        self.imageV.layer.transform = CATransform3DMakeRotation(M_PI, 1, 1, 0);
        
        // 把结构体换成对象
        NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 1, 0)];
        
        // 第二种设置方式:
        // 我们一般通过KVC做快速旋转。平移,缩放
        [self.imageV.layer setValue:@(M_PI) forKey:@"transform.rotation.x"];
    }];
}

<b>在第二种方法中,forKey的值不是随便填写的,它在CATransform3D Key Paths中有规定</b>

Field Key Path Description
rotation.x Set to an NSNumber object whose value is the rotation, in radians, in the x axis.
rotation.y Set to an NSNumber object whose value is the rotation, in radians, in the y axis.
rotation.z Set to an NSNumber object whose value is the rotation, in radians, in the z axis.
rotation Set to an NSNumber object whose value is the rotation, in radians, in the z axis. This field is identical to setting the rotation.z field.
scale.x Set to an NSNumber object whose value is the scale factor for the x axis.
scale.y Set to an NSNumber object whose value is the scale factor for the y axis.
scale.z Set to an NSNumber object whose value is the scale factor for the z axis.
scale Set to an NSNumber object whose value is the average of all three scale factors.
translation.x Set to an NSNumber object whose value is the translation factor along the x axis.
translation.y Set to an NSNumber object whose value is the translation factor along the y axis.
translation.z Set to an NSNumber object whose value is the translation factor along the z axis.
translation Set to an NSValue object containing an NSSize or CGSize data type. That data type indicates the amount to translate in the x and y axis.

<h5>UIView和CALayer的选择</h5>

使用Layer展示一张图片

    
    CALayer *layer = [[CALayer alloc] init];
    layer.backgroundColor = [UIColor brownColor].CGColor;
    layer.frame = CGRectMake(100, 100, 100, 100);
    
    [self.view.layer addSublayer:layer];
    
    layer.contents = (id)[UIImage imageNamed:@"123.png"].CGImage;

<b>关于CALayer的疑惑</b>

<b>UIView和CALayer的选择</b>

<h5>position和anchorPoint</h5>

<b>CALayer有2个非常重要的属性:positionanchorPoint</b>

<b> UIView的center和layer的position是一个点</br>
position和anchorPoint 点重合</b>

<h5>隐式动画</h5>

         // 只有非根层才有隐式动画(自己手动创建)
         [CATransaction  begin];
         [CATransaction setAnimationDuration: 2.0];
         [CATransaction  setDisableActions:YES];

         [CATransaction  commit];

<b>挂钟案例</b>

// 在storyboard中拖一个UIImageView并确定宽高相同,然后拖线,然后添加图片
@property (weak, nonatomic) IBOutlet UIImageView *clockView;

/** 当前的秒针 */
@property (nonatomic, strong) CALayer *secondLayer;
/** 当前的分针 */
@property (nonatomic, strong) CALayer *minuteLayer;
/** 当前的时针 */
@property (nonatomic, strong) CALayer *hourLayer;
// 代码中用到的宏
//每一秒旋转的度数
#define perSecondAngle 6
//每一分旋转的度数
#define perMinuteAngle 6
//每一分旋转的度数
#define perHourAngle 30

// 每一分钟,时针旋转的角度
#define perMinuteWithHourRotateAngle 0.5

// 角度转弧度的宏
#define angle2radian(angle) ((angle) / 180.0 * M_PI)
- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setHourLayer];

    [self setMinuteLayer];

    [self setSecondLayer];
    
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
    
    // 为了防止刚开始,秒针跳一下,在加载的时候就调用一次,
    [self timeChange];  
}
- (void)timeChange {

    NSCalendar *calendar = [NSCalendar currentCalendar];
    // components: 是日历的组件, 年,月,日,时,分,秒
    //fromDate: 从什么时间开始获取
    NSDateComponents *dateComponents = [calendar components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour fromDate:[NSDate date]];
    
    // 获取当前是多少秒
    NSInteger currentSecond = dateComponents.second + 1;
    
    // 秒针开始旋转
    // 计算秒针当前旋转的角度
    // angle = 当前多少秒 * 每一秒旋转的角度
    CGFloat secondAngle = currentSecond * perSecondAngle;
    self.secondLayer.transform = CATransform3DMakeRotation(angle2radian(secondAngle), 0, 0, 1);
    
    // 获取当前是多少分
    NSInteger currentMinute = dateComponents.minute;
    
    // 分针开始旋转
    // 计算秒针当前旋转的角度
    // angle = 当前多少分 * 每一分旋转的角度
    CGFloat minuteAngle = currentMinute * perMinuteAngle;
    self.minuteLayer.transform = CATransform3DMakeRotation(angle2radian(minuteAngle), 0, 0, 1);
    
    // 获取当前是多少小时
    NSInteger currentHour = dateComponents.hour;
    
    // 分针开始旋转
    // 计算秒针当前旋转的角度
    // angle = 当前多少小时 * 每一小时旋转的角度
    CGFloat hourAngle = currentHour * perHourAngle + currentMinute * perMinuteWithHourRotateAngle;
    self.hourLayer.transform = CATransform3DMakeRotation(angle2radian(hourAngle), 0, 0, 1);
    
}
// // 添加秒针
- (void)setSecondLayer {
    
    CALayer *secondLayer = [CALayer layer];
    secondLayer.bounds = CGRectMake(0, 0, 1, 80);
    secondLayer.backgroundColor = [UIColor redColor].CGColor;
    secondLayer.anchorPoint = CGPointMake(0.5, 1);
    secondLayer.position = CGPointMake(self.clockView.bounds.size.width * 0.5, self.clockView.bounds.size.height * 0.5);
    [self.clockView.layer addSublayer:secondLayer];
    self.secondLayer = secondLayer;
}
// // 添加分针
- (void)setMinuteLayer {
    
    CALayer *minuteLayer = [CALayer layer];
    minuteLayer.bounds = CGRectMake(0, 0, 2, 70);
    minuteLayer.backgroundColor = [UIColor blackColor].CGColor;
    minuteLayer.cornerRadius = 1.5;
    minuteLayer.anchorPoint = CGPointMake(0.5, 1);
    minuteLayer.position = CGPointMake(self.clockView.bounds.size.width * 0.5, self.clockView.bounds.size.height * 0.5);
    [self.clockView.layer addSublayer:minuteLayer];
    
    self.minuteLayer = minuteLayer;
}
// // 添加时针
- (void)setHourLayer {
    
    CALayer *hourLayer = [CALayer layer];
    hourLayer.bounds = CGRectMake(0, 0, 3, 50);
    hourLayer.backgroundColor = [UIColor blackColor].CGColor;
    hourLayer.cornerRadius = 1.5;
    hourLayer.anchorPoint = CGPointMake(0.5, 1);
    hourLayer.position = CGPointMake(self.clockView.bounds.size.width * 0.5, self.clockView.bounds.size.height * 0.5);
    [self.clockView.layer addSublayer:hourLayer];
    
    self.hourLayer = hourLayer;
}

<h5>Core Animation</h5>

<h5>核心动画继承结构</h5>

<b>注意:图中的黑色虚线代表“继承”某个类,红色虚线代表“遵守”某个协议</b>


核心动画继承结构.png

<h5>Core Animation的使用步骤</h5>

<h5>CAAnimation——简介</h5>

<b>CAAnimation——动画填充模式</b>

<b>CAAnimation——速度控制函数</b>

<b>CAAnimation——动画代理方法</b>

@interfaceNSObject(CAAnimationDelegate)

/*Called when the animation begins its active duration. */

-(void)animationDidStart:(CAAnimation*)anim;

/*Called when the animation either completes its active duration or
 * is removed from the object it is attached to(i.e. the layer). 'flag'
 * is true if the animation reached the end ofits active duration
 * without being removed. */

-(void)animationDidStop:(CAAnimation*)animfinished:(BOOL)flag;

@end

<h5>CABasicAnimation(基础动画)基本使用</h5>

简单心跳制作

// storyboard中拖一个200*200的ImageView,并拖线
@property (weak, nonatomic) IBOutlet UIImageView *imageV;

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

    // 1.创建动画对象
    CABasicAnimation *basicAnimation = [CABasicAnimation animation];
    
    // 2.设置动画属性值
    basicAnimation.keyPath = @"transform.scale";
    basicAnimation.toValue = @0;
    
    // 设置动画执行的次数
    basicAnimation.repeatCount = MAXFLOAT;
    
    // 设置动画执行长度
    basicAnimation.duration = 1;
    
    // 自动翻转(怎么样去,怎么样回来)
    basicAnimation.autoreverses = YES;
    
    /**
     // 3.添加动画
     
     @param CAAnimation 动画对象
     @param NSString (forKey)添加动画组需要用到的标识
     */
    [self.imageV.layer addAnimation:basicAnimation forKey:nil];
}

呈现效果:


简单心跳制作.gif

<h5>CAKeyframeAnimation(帧动画)基本使用</h5>

简单制作卸载程序的抖动效果

// 1.第一种简单使用,values——
/** 角度转弧度 */
#define angle2radian(angle) ((angle) / 180.0 * M_PI)
@property (weak, nonatomic) IBOutlet UIImageView *iconV;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    // 1.创建动画
    CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animation];
    
    // 2.设置动画属性值
    keyframeAnimation.keyPath = @"transform.rotation";
    keyframeAnimation.values = @[@(angle2radian(-5)), @(angle2radian(5)), @(angle2radian(-5))];
    
    keyframeAnimation.repeatCount = MAXFLOAT;
    keyframeAnimation.duration = 0.2;
    
//    keyframeAnimation.autoreverses = YES;
    
    [self.iconV.layer addAnimation:keyframeAnimation forKey:nil];
}

呈现效果:


图标抖动.gif
// 2.第二种简单使用,path——
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    // 1.创建动画
    CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animation];
    
    keyframeAnimation.duration = 2;
    keyframeAnimation.autoreverses = YES;
    keyframeAnimation.repeatCount = MAXFLOAT;
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(50, 70)];
    [path addLineToPoint:CGPointMake(300, 100)];
    [path addLineToPoint:CGPointMake(100, 90)];
    
    keyframeAnimation.keyPath = @"position";
    keyframeAnimation.path = path.CGPath;
    
    [self.iconV.layer addAnimation:keyframeAnimation forKey:nil];
}

呈现效果:


图标沿路径做动画.gif

<h5>CATransition(转场动画)基本使用</h5>

// storyboard创建ImageView设置宽高,并拖线
@property (weak, nonatomic) IBOutlet UIImageView *photoV;

static int _i = 0;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    // 转场代码和转场动画必须得在同一个方法中
    // // 转场代码
    _i++;
    if (_i == 5) {
        _i = 0;
    }
    NSString *imageName = [NSString stringWithFormat:@"%d", _i];
    self.photoV.image = [UIImage imageNamed:imageName];
    
    // // 转场动画
    // 添加动画
    CATransition *transitionAnimation = [CATransition animation];
    
    // 设置转场动画
    transitionAnimation.type = @"rippleEffect";
    
    // 设置动画的起始位置 ------+++------
    transitionAnimation.startProgress = 0.3;
    // 设置动画的结束位置 ------+++------
    transitionAnimation.endProgress = 0.5;
    
    transitionAnimation.duration = 1;
    
    [self.photoV.layer addAnimation:transitionAnimation forKey:nil];
}

呈现效果:


转场动画.gif

<b>转场动画过渡效果</b>

类型字符串 效果说明 关键字 方向
fade 交叉淡化过渡 YES
push 新视图把旧视图推出去 YES
moveIn 新视图移到旧视图上面 YES
reveal 将旧视图移开,显示下面的新视图 YES
cube 立方体翻滚效果
oglFlip 上下左右翻转效果
suckEffect 收缩效果,如一块布被抽走 NO
rippleEffect 水滴效果 NO
pageCurl 向上翻页效果
pageUnCurl 向下翻页效果
cameraIrisHollowOpen 相机镜头打开效果 NO
cameraIrisHollowClose 相机镜头关闭效果 NO

<h5>CAAnimationGroup(动画组)基本使用</h5>

@property (weak, nonatomic) IBOutlet UIView *colorView;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    CABasicAnimation *basicAnimation01 = [CABasicAnimation animation];
    basicAnimation01.keyPath = @"position.y";
    basicAnimation01.toValue = @300;
    
//    basicAnimation01.removedOnCompletion = NO;
//    basicAnimation01.fillMode = kCAFillModeForwards;
//    
//    [self.colorView.layer addAnimation:basicAnimation01 forKey:nil];
    
    CABasicAnimation *basicAnimation02 = [CABasicAnimation animation];
    basicAnimation02.keyPath = @"transform.scale";
    basicAnimation02.toValue = @0.5;
    
//    basicAnimation02.removedOnCompletion = NO;
//    basicAnimation02.fillMode = kCAFillModeForwards;
//    
//    [self.colorView.layer addAnimation:basicAnimation02 forKey:nil];
    
    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    // 会自动执行animations数组当中的所有动画对象
    animationGroup.animations = @[basicAnimation01, basicAnimation02];
    
    animationGroup.removedOnCompletion = NO;
    animationGroup.fillMode = kCAFillModeForwards;
    
    [self.colorView.layer addAnimation:animationGroup forKey:nil];
}

呈现效果:


动画组.gif

<h5>UIView与核心动画区别</h5>

  1. 核心动画只作用在layer上
  2. 核心动画看到的都是假象,它并没有修改UIView的真实位置

<b>什么时候使用核心动画</b>

  1. 当不需要与用户进行交互的时候,使用核心动画
  2. 当需要根据路径做动画的时候,使用核心动画
  3. 当作转场动画时,使用核心动画(转场类型比较多)
上一篇 下一篇

猜你喜欢

热点阅读