前言
I 使用CALayer 实现时钟
1.1 视图结构
@property (weak, nonatomic) IBOutlet UIImageView *clockView;
@property (weak,nonatomic) CALayer *secondLayer;
@property (weak,nonatomic) CALayer *minuteLayer;
@property (weak,nonatomic) CALayer
1.2 代码实现
- (void)viewDidLoad {
[super viewDidLoad];
[self layerRotation];
//开启定时器
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(layerRotation) userInfo:nil repeats:YES];
}
#pragma
- (void)layerRotation {
//获取秒数
NSCalendar *calendar = [NSCalendar currentCalendar];//获取日历对象
NSDateComponents *components = [calendar components:NSCalendarUnitSecond| NSCalendarUnitHour|NSCalendarUnitMinute fromDate:[NSDate date]];
CGFloat second = components.second;
//计算当前的秒针对应的弧度
CGFloat secondAngle = second *KHSPerSecondAngle;
//1、旋转秒针
[self.secondLayer setTransform:CATransform3DMakeRotation(angle2radian(secondAngle), 0, 0, 1)];
//KVC--有bug
// [self.secondLayer setValue:@angle2radian(secondAngle) forKeyPath:@"transform.rotation"];
//2、旋转分针
CGFloat minute = components.minute;
CGFloat minuteAngle = minute *KHSPerMinuteAngle +second*(KHSPerMinuteAngle/60.0);//整分+秒的弧度(每秒对应的0.1弧度)
[self.minuteLayer setTransform:CATransform3DMakeRotation(angle2radian(minuteAngle), 0, 0, 1)];
//3、旋转时针
CGFloat hour = components.hour;
//计算当前的秒针对应的弧度
CGFloat hourAngle = hour *KHSPerHourAngle + minute*(KHSPerHourAngle/60.0) +second*(KHSPerHourAngle/360.0);//整点的角度+分钟的角度+秒的弧度(2分钟=1弧度=》1个小时=30弧度)
[self.hourLayer setTransform:CATransform3DMakeRotation(angle2radian(hourAngle), 0, 0, 1)];
}
II CALayer 是显示的基础:存储 bitmap
CALayer 是屏幕显示的基础,在 CALayer.h 中,CALayer 有这样一个属性 contents:
/** Layer content properties and methods. **/
/* An object providing the contents of the layer, typically a CGImageRef,
* but may be something else. (For example, NSImage objects are
* supported on Mac OS X 10.6 and later.) Default value is nil.
* Animatable. */
@property(nullable, strong) id
An object providing the contents of the layer, typically a CGImageRef.
contents 提供了 layer 的内容,是一个指针类型,在 iOS 中的类型就是 CGImageRef(在 OS X 中还可以是 NSImage)。而我们进一步查到,Apple 对 CGImageRef 的定义是:
A bitmap image or image mask.
看到 bitmap,这下我们就可以和之前讲的的渲染流水线联系起来了:实际上,CALayer 中的 contents 属性保存了由设备渲染流水线渲染好的位图 bitmap(通常也被称为 backing store),而当设备屏幕进行刷新时,会从 CALayer 中读取生成好的 bitmap,进而呈现到屏幕上。
所以,如果我们在代码中对 CALayer 的 contents 属性进行了设置,比如这样:
// 注意 CGImage 和 CGImageRef 的关系:
// typedef struct CGImage CGImageRef;
layer.contents = (__bridge id)image.CGImage;**
那么在运行时,操作系统会调用底层的接口,将 image 通过 CPU+GPU 的渲染流水线渲染得到对应的 bitmap,存储于 CALayer.contents 中,在设备屏幕进行刷新的时候就会读取 bitmap 在屏幕上呈现。
也正因为每次要被渲染的内容是被静态的存储起来的,所以每次渲染时,Core Animation 会触发调用drawRect:
方法,使用存储好的 bitmap 进行新一轮的展示。
III CALayer 与 UIView 的关系
- UIView 是 app 中的基本组成结构,定义了一些统一的规范。它会负责
内容的渲染以及处理交互事件
。
具体而言,它负责的事情归为下面三类:
Drawing and animation:绘制与动画
Layout and subview management:布局与子 view 的管理 Event handling:点击事件处理
- CALayer 的主要职责是:
管理内部的可视内容
。
当我们创建一个 UIView 的时候,UIView 会自动创建一个 CALayer,为自身提供存储 bitmap 的地方(也就是前文说的 backing store),并将自身固定设置为 CALayer 的代理。
两者的职责分离,拆分功能,目的是方便代码的复用。
通过 Core Animation 框架来负责可视内容的呈现,这样在 iOS 和 OS X 上都可以使用 Core Animation 进行渲染。与此同时,两个系统还可以根据交互规则的不同来进一步封装统一的控件,比如 iOS 有 UIKit 和 UIView,OS X 则是AppKit 和 NSView。
3.1 核心关系
- CALayer 是 UIView 的属性之一,负责渲染和动画,提供可视内容的呈现。
- UIView 提供了对 CALayer 部分功能的封装,同时也另外负责了交互事件的处理。
- 相同的层级结构:我们对 UIView 的层级结构非常熟悉,由于每个 UIView 都对应 CALayer 负责页面的绘制,所以 CALayer 也具有相应的层级结构。
3.2 不同点
- UIView只支持部分效果的设置:因为 UIView 只对 CALayer 的部分功能进行了封装,而另一部分如圆角、阴影、边框等特效都需要通过调用 layer 属性来设置。
- CALayer 不负责点击事件,所以不响应点击事件,而 UIView 会响应。
- 不同继承关系:CALayer 继承自 NSObject,UIView 由于要负责交互事件,所以继承自 UIResponder。
see aslo
- html进阶:【Meta 标签的 http-equiv 属性使用指南】
iOS逆向(公号:iosrev)
简历模板、技术互助。关注我,都给你。