6.2 核心动画->3.0 核心动画 & UIVi
本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正。
本文相关目录:
===================== 所属文集:6.0 图形和多媒体 =====================
6.2 核心动画->1.0 CALayer的简介
6.2 核心动画->1.1 CALayer的基本属性
6.2 核心动画->1.2 CALayer的创建 & 非根layer的隐式动画
6.2 核心动画->2.0 Core Animation(核心动画)
6.2 核心动画->3.0 核心动画 & UIView动画
6.2 核心动画->4.0 常用动画效果
===================== 所属文集:6.0 图形和多媒体 =====================
核心动画代码示例:
#import "ViewController.h"
@interface ViewController ()
@property(weak, nonatomic) IBOutlet UIView *redView;
@end
@implementation ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath = @"position";
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(150, 400)];
// 注意:取消反弹代码必须放在图层添加动画之前。
anim.removedOnCompletion = NO;
// 设置保存动画的最新状态,图层会保持显示动画执行后的状态
anim.fillMode = kCAFillModeForwards;
//(不需要遵守协议)设置代理,动画执行完毕后会调用delegate的animationDidStop:finished:
anim.delegate = self;
[_redView.layer addAnimation:anim forKey:nil];
}
#pragma mark - 动画完成的时候调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
// 打印图层的位置的CGPoint
NSLog(@"动画完成:%@", NSStringFromCGPoint(_redView.layer.position));
}
- (void)viewDidLoad {
[super viewDidLoad];
// 打印图层的位置的CGPoint
NSLog(@"原始位置:%@", NSStringFromCGPoint(_redView.layer.position));
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
运行效果:

打印结果:
核心动画[1112:36378] 原始位置:{135, 122}
核心动画[1112:36378] 动画完成:{135, 122}
结论:核心动画一切都是假象,并不会真实的改变图层的属性值,如果以后做动画的时候,不需要与用户交互,通常用核心动画(如:转场动画)。
UIView动画代码示例:
#import "ViewController.h"
@interface ViewController ()
@property(weak, nonatomic) IBOutlet UIView *redView;
@end
@implementation ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:0.25
animations:^{
_redView.layer.position = CGPointMake(150, 400);
}
completion:^(BOOL finished) {
// 动画完成的时候,打印图层的位置的CGPoint
NSLog(@"动画完成:%@", NSStringFromCGPoint(_redView.layer.position));
}];
}
- (void)viewDidLoad {
[super viewDidLoad];
// 打印图层的位置的CGPoint
NSLog(@"原始位置:%@", NSStringFromCGPoint(_redView.layer.position));
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
结论:UIView动画必须通过修改属性的真实值,才有动画效果。
运行效果:

打印结果:
UIView动画[1258:43954] 原始位置:{133, 109}
UIView动画[1258:43954] 动画完成:{150, 400}
结论:UIView动画必须通过修改属性的真实值,才有动画效果。
核心动画案例 - 钟表动画
问题描述:通过 NSTimer 实现的动画可能造成卡顿、不连贯的情况(NSTimer 不准确)
解决方法:通过 CADisplayLink 来解决,CADisplayLink 表示"显示连接", 与显示器的刷新频率相关。
CADisplayLink:
- CADisplayLink是一种以屏幕刷新频率触发的时钟机制,每秒钟执行大约60次左右
- CADisplayLink是一个计时器,可以使绘图代码与视图的刷新频率保持同步,而NSTimer无法确保
计时器实际被触发的准确时间
使用方法:
- 定义CADisplayLink并制定触发调用方法
- 将显示链接添加到主运行循环队列
代码示例:
#define kClockW _clockView.bounds.size.width
#define angle2radion(a) ((a) / 180.0 * M_PI) // 角度转弧度
#define perSecondA 6 // 一秒钟秒针转6°
#define perMinuteA 6 // 一分钟分针转6°
#define perHourA 30 // 一小时时针转30°
// 每分钟时针转多少度
#define perMinuteHour A 0.5
#import "ViewController.h"
@interface ViewController ()
@property(weak, nonatomic) IBOutlet UIImageView *clockView;
@property(nonatomic, weak) CALayer *secondLayer; // 秒针
@property(nonatomic, weak) CALayer *minuteLayer; // 分针
@property(nonatomic, weak) CALayer *hourLayer; // 时针
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpHourLayer]; // 添加时针
[self setUpMinuteLayer]; // 添加分针
[self setUpSecondLayer]; // 添加秒针
// 方式1:NSTimer定时器
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(timeChange)
userInfo:nil
repeats:YES];
[self timeChange];
// 方法2:CADisplayLink(link默认是1/60 秒执行一次)
CADisplayLink *link =
[CADisplayLink displayLinkWithTarget:self selector:@selector(timeChange)];
//执行定时器 把定时器放在主运行循环中执行
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
// 获取当前的系统的时间
- (void)timeChange {
// 获取当前日历对象
NSCalendar *calendar = [NSCalendar currentCalendar];
// 获取日期的组件:年月日时分秒
// components:需要获取的日期组件 fromDate:获取哪个日期的组件
// 经验:以后枚举中有移位运算符,通常一般可以使用并运算(|)
NSDateComponents *cmp =
[calendar components:NSCalendarUnitSecond | NSCalendarUnitMinute |
NSCalendarUnitHour
fromDate:[NSDate date]]; // 获取当前日期的组件
// 获取秒
NSInteger second = cmp.second;
// 获取分
NSInteger minute = cmp.minute;
// 获取小时
NSInteger hour = cmp.hour;
// 计算秒针转多少度
CGFloat secondA = second * perSecondA;
// 计算分针转多少度
CGFloat minuteA = minute * perMinuteA;
// 计算时针转多少度
CGFloat hourA = hour * perHourA + minute * perMinuteHourA;
// 旋转秒针
_secondLayer.transform =
CATransform3DMakeRotation(angle2radion(secondA), 0, 0, 1);
// 旋转分针
_minuteLayer.transform =
CATransform3DMakeRotation(angle2radion(minuteA), 0, 0, 1);
// 旋转小时
_hourLayer.transform =
CATransform3DMakeRotation(angle2radion(hourA), 0, 0, 1);
}
#pragma mark - 添加秒针
- (void)setUpSecondLayer {
// 创建秒针
CALayer *secondL = [CALayer layer];
// 秒针背景色
secondL.backgroundColor = [UIColor redColor].CGColor;
// 设置锚点
secondL.anchorPoint = CGPointMake(0.5, 1);
// 设置位置
secondL.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
// 设置 bounds
secondL.bounds = CGRectMake(0, 0, 1, kClockW * 0.5 - 20);
// 添加到 view 上
[_clockView.layer addSublayer:secondL];
_secondLayer = secondL;
}
#pragma mark - 添加分针
- (void)setUpMinuteLayer {
// 创建分针
CALayer *layer = [CALayer layer];
// 分针背景色
layer.backgroundColor = [UIColor blackColor].CGColor;
// 设置锚点
layer.anchorPoint = CGPointMake(0.5, 1);
// 设置位置
layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
// 设置 bounds
layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 20);
// 设置圆角半径
layer.cornerRadius = 4;
[_clockView.layer addSublayer:layer];
_minuteLayer = layer;
}
#pragma mark - 添加时针
- (void)setUpHourLayer {
// 创建时针
CALayer *layer = [CALayer layer];
layer.backgroundColor = [UIColor blackColor].CGColor;
// 设置锚点
layer.anchorPoint = CGPointMake(0.5, 1);
layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 40);
layer.cornerRadius = 4;
[_clockView.layer addSublayer:layer];
_hourLayer = layer;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
运行效果:

本文源码 Demo 详见 Github
https://github.com/shorfng/iOS_6.0_Graphics_and_multimedia.git
作者:蓝田(Loto)
出处: 简书
如果你觉得本篇文章对你有所帮助,请点击文章末尾下方“喜欢”
如有疑问,请通过以下方式交流:
① 评论区回复
② 微信(加好友请注明“简书+称呼”)
③发送邮件
至 shorfng@126.com
本文版权归作者和本网站共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。