作者:@武蕴牛x 授权本站转载。 前言 前面发了一篇iOS 面试的文章,在说到 UIView 和 CALayer 的区别和联系的时候,被喵神指出没有切中要点,所以这里就 CALayer 和 UIView 这个问题重新整理了下。这里会先分条解释,最后会在文章的结尾给出概括性总结。 1.首先UIView可以响应事件,Layer不可以. UIKit使用UIResponder作为响应对象,来响应系统传递过来的事件并进行处理。UIApplication、UIViewController、UIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。 在 UIResponder中定义了处理各种事件和事件传递的接口, 而 CALayer直接继承 NSObject,并没有相应的处理事件的接口。 下面列举一些处理触摸事件的接口
其实还有一些运动和远程控制事件等等,这里就不一一列举了。 下面的两篇文章详细介绍了 iOS 事件的处理和传递 参考链接: 2.View和CALayer的Frame映射及View如何创建CALayer. 一个 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同决定的,而一个 View 的 frame 只是简单的返回 Layer的 frame,同样 View 的 center和 bounds 也是返回 Layer 的一些属性。(PS:center有些特列)为了证明这些,我做了如下的测试。 首先我自定义了两个类CustomView,CustomLayer分别继承 UIView 和 CALayer 在 CustomView 中重写了 + (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方法 我在两个类的初始化方法中都打下了断点 首先我们会发现,我们在 [view initWithFrame] 的时候调用私有方法【UIView _createLayerWithFrame】去创建 CALayer。 然后我在创建 View 的时候,在 Layer 和 View 中Frame 相关的所有方法中都加上断点,可以看到大致如下的调用顺序如下 [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./industry/20131209/7498.html 3.UIView主要是对显示内容的管理而 CALayer 主要侧重显示内容的绘制。 我在 UIView 和 CALayer 分别重写了父类的方法。 [UIView drawRect:rect]//UIView [CALayer display]//CALayer 然后我在上面两个方法加了断点,可以看到如下的执行。 可以看到 UIView 是 CALayer 的CALayerDelegate,我猜测是在代理方法内部[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 可以通过返回以下三者之一来进行响应:
当 layer 在背后支持一个 view 的时候,view 就是它的 delegate; 这部分的具体内容参考:http:///issue-12-4/ 总结 总接来说就是如下几点:
参考链接 |
|