0
点赞
收藏
分享

微信扫一扫

iOS小技能:使用CALayer 实现时钟(CALayer 与 UIView 的关系)

前言

iOS小技能:使用CALayer 实现时钟(CALayer 与 UIView 的关系)_封装

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 的代理。

iOS小技能:使用CALayer 实现时钟(CALayer 与 UIView 的关系)_ios_02

​两者的职责分离,拆分功能,目的是方便代码的复用。​

通过 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 不同点

  1. UIView只支持部分效果的设置:因为 UIView 只对 CALayer 的部分功能进行了封装,而另一部分如圆角、阴影、边框等特效都需要通过调用 layer 属性来设置。
  2. CALayer 不负责点击事件,所以不响应点击事件,而 UIView 会响应。
  3. 不同继承关系:CALayer 继承自 NSObject,UIView 由于要负责交互事件,所以继承自 UIResponder。

see aslo

  • html进阶:【Meta 标签的 http-equiv 属性使用指南】

iOS逆向(公号:iosrev)

简历模板、技术互助。关注我,都给你。


举报

相关推荐

0 条评论