详解 CALayer 和 UIView 的区别和联系

news/2024/7/20 21:59:41 标签: iOS, CALayer, UIView

pexels-photo-large.jpeg

作者:@武蕴牛x 授权本站转载。

前言

前面发了一篇iOS 面试的文章,在说到 UIViewCALayer 的区别和联系的时候,被喵神指出没有切中要点,所以这里就 CALayerUIView 这个问题重新整理了下。这里会先分条解释,最后会在文章的结尾给出概括性总结。

1.首先UIView可以响应事件,Layer不可以.

UIKit使用UIResponder作为响应对象,来响应系统传递过来的事件并进行处理。UIApplication、UIViewController、UIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。

在 UIResponder中定义了处理各种事件和事件传递的接口, 而 CALayer直接继承 NSObject,并没有相应的处理事件的接口。

下面列举一些处理触摸事件的接口

  • – touchesBegan:withEvent:

  • – touchesMoved:withEvent:

  • – touchesEnded:withEvent:

  • – touchesCancelled:withEvent:

其实还有一些运动和远程控制事件等等,这里就不一一列举了。

下面的两篇文章详细介绍了 iOS 事件的处理和传递

参考链接:

  • http://blog.csdn.net/chun799/article/details/8223612

  • http://yishuiliunian.gitbooks.io/implementate-tableview-to-understand-ios/content/uikit/1-1-2.html

2.View和CALayer的Frame映射及View如何创建CALayer.

一个 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同决定的,而一个 View 的 frame 只是简单的返回 Layer的 frame,同样 View 的 center和 bounds 也是返回 Layer 的一些属性。(PS:center有些特列)为了证明这些,我做了如下的测试。

首先我自定义了两个类CustomView,CustomLayer分别继承 UIViewCALayer

在 CustomView 中重写了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
+ (Class)layerClass
{
     return  [CustomLayer class];
}
- (void)setFrame:(CGRect)frame
{
     [ super  setFrame:frame];
}
- (void)setCenter:(CGPoint)center
{
     [ super  setCenter:center];
}
- (void)setBounds:(CGRect)bounds
{
     [ super  setBounds:bounds];
}

同样在 CustomLayer中同样重写这些方法。只是 setCenter方法改成setPosition方法

我在两个类的初始化方法中都打下了断点

blob.png

首先我们会发现,我们在 [view initWithFrame] 的时候调用私有方法【UIView _createLayerWithFrame】去创建 CALayer

然后我在创建 View 的时候,在 Layer 和 View 中Frame 相关的所有方法中都加上断点,可以看到大致如下的调用顺序如下

1
2
3
4
5
6
[UIView _createLayerWithFrame]
[Layer setBounds:bounds]
[UIView setFrame:Frame]
[Layer setFrame:frame]
[Layer setPosition:position]
[Layer setBounds:bounds]

我发现在创建的过程只有调用了 Layer 的设置尺寸和位置的然而并没有调用View 的 SetCenter 和 SetBounds 方法。

然后我发现当我修改了 view的 bounds.size 或者 bounds.origin 的时候也只会调用上边 Layer的一些方法。所以我大胆的猜一下,View 的 Center 和 Bounds 只是直接返回layer 对应的 Position 和 Bounds.

View中frame getter方法,bounds和center,UIView并没有做什么工作;它只是简单的各自调用它底层的CALayer的frame,bounds和position方法。

关于 Frame 的理解参考:http://www.cocoachina.com/industry/20131209/7498.html

3.UIView主要是对显示内容的管理而 CALayer 主要侧重显示内容的绘制。

我在 UIViewCALayer 分别重写了父类的方法。

1
2
[UIView drawRect:rect] //UIView    
[CALayer display] //CALayer

然后我在上面两个方法加了断点,可以看到如下的执行。

blob.png

可以看到 UIViewCALayerCALayerDelegate,我猜测是在代理方法内部[UIView(CALayerDelegate) drawLayer:inContext]调用 UIView 的 DrawRect方法,从而绘制出了 UIView 的内容.

4.在做 iOS 动画的时候,修改非 RootLayer的属性(譬如位置、背景色等)会默认产生隐式动画,而修改UIView则不会。

对于每一个 UIView 都有一个 layer,把这个 layer 且称作RootLayer,而不是 View 的根 Layer的叫做 非 RootLayer。我们对UIView的属性修改时时不会产生默认动画,而对单独 layer属性直接修改会,这个默认动画的时间缺省值是0.25s.

在 Core Animation 编程指南的 “How to Animate Layer-Backed Views” 中,对为什么会这样做出了一个解释:

UIView 默认情况下禁止了 layer 动画,但是在 animation block 中又重新启用了它们

是因为任何可动画的 layer 属性改变时,layer 都会寻找并运行合适的 'action' 来实行这个改变。在 Core Animation 的专业术语中就把这样的动画统称为动作 (action,或者 CAAction)。

layer 通过向它的 delegate 发送 actionForLayer:forKey: 消息来询问提供一个对应属性变化的 action。delegate 可以通过返回以下三者之一来进行响应:

  1. 它可以返回一个动作对象,这种情况下 layer 将使用这个动作。

  2. 它可以返回一个 nil, 这样 layer 就会到其他地方继续寻找。

  3. 它可以返回一个 NSNull 对象,告诉 layer 这里不需要执行一个动作,搜索也会就此停止。

当 layer 在背后支持一个 view 的时候,view 就是它的 delegate;

这部分的具体内容参考:http://objccn.io/issue-12-4/

总结

总接来说就是如下几点:

  • 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint

  • 在 View显示的时候,UIView 做为 Layer 的 CALayerDelegate,View 的显示内容由内部的 CALayer 的 display

  • CALayer 是默认修改属性支持隐式动画的,在给 UIView 的 Layer 做动画的时候,View 作为 Layer 的代理,Layer 通过 actionForLayer:forKey:向 View请求相应的 action(动画行为)

  • layer 内部维护着三分 layer tree,分别是 presentLayer Tree(动画树),modeLayer Tree(模型树), Render Tree (渲染树),在做 iOS动画的时候,我们修改动画的属性,在动画的其实是 Layer 的 presentLayer的属性值,而最终展示在界面上的其实是提供 View的modelLayer

  • 两者最明显的区别是 View可以接受并处理事件,而 Layer 不可以

参考链接

  • http://blog.csdn.net/weiwangchao_/article/details/7771538


http://www.niftyadmin.cn/n/704776.html

相关文章

ZooKeeper系列(3):znode说明和znode状态

ZooKeeper系列文章:https://www.cnblogs.com/f-ck-need-u/p/7576137.html#zk 1.znode znode的官方说明:http://zookeeper.apache.org/doc/r3.4.12/zookeeperProgrammers.html#sc_zkDataModel_znodes ZooKeeper以一种类似于文件系统的树形数据结构实现名称…

iPhone屏幕尺寸、分辨率及适配-曾梦想仗剑走天涯

1.iPhone尺寸规格 设备 iPhone 宽 Width 高 Height 对角线 Diagonal 逻辑分辨率(point) Scale Factor 设备分辨率(pixel) PPI 3GS 2.4 inches (62.1 mm) 4.5 inches (115.5 mm) 3.5-inch 320x480 1x 320x480 163 4(s) 2.31 inches (5…

酷狗音乐获取hush值方法

关键词抓取歌曲列表,获取hash http://mobilecdn.kugou.com/api/v3/search/song?formatjson&keyword%E6%88%91%E4%BB%AC%E4%B8%8D%E4%B8%80%E6%A0%B7&page1&pagesize20&showtype1 {"status":1,"error":"","data…

idea集成项目管理工具 --- Maven 并且【配置tomcat】

介绍: 1.项目管理工具 POM Porject Object Model 2.可以管理项目中的的jar包依赖 3.maven jar包中央仓库:http://mvnrepository.com/ 项目结构体系: 安装: 安装包下载地址:http://maven.apache.org/ 配置环境变量…

django restframework serializer 增加自定义字段

在使用django restframework serializer 序列化在django中定义的model时,有时候我们需要额外在serializer中增加一些model中没有的字段。有两种方法实现这个目的。 假设现在有一个Animal模型,其中有name, type, country字段,country为外键。我…

我是这么理解Vue中的响应式系统的

遇到知识,尤其是复杂的概念,我不能类比的话,我很难接收(所以学习很差...)。在看了大神染陌同学的Vue源码解析后,我想分享一下我所类比的Vue响应式系统,您得先看他的文章(至少看他写的…

Quota磁盘配额

实验环境:VMwareWorkstation上的虚拟机linux系统;实验要求:对用户zhangsan实现磁盘配额,大小50k,文件个数5个;实验步骤:一、在虚拟机Rhel6(linux系统)上新建硬盘&#xf…

二分类、多分类与多标签问题的区别,对应损失函数的选择,你知道吗?

二分类、多分类与多标签分类问题使用不同的激活函数和损失函数,结论见文末总结(如果你赶时间可以直接看结论,但建议有时间时回过头来看看分析更有助于理解)。 更多人工智能基础知识见 望江小车车的博客 二分类、多分类与多标签的基…