是否使用自定义绘图代码drawLayer(_:inContext:)
或drawRect(_:)
(或同时使用)自定义绘图代码取决于是否需要在动画化图层属性时访问其当前值。
今天,当实现自己的Label类时,我在与这两个函数相关的各种渲染问题上苦苦挣扎。在检查了文档之后,进行了反复试验,反编译了UIKit并检查了Apple的Custom Animatable Properties示例,我对它的工作方式有了很好的了解。
drawRect(_:)
如果不需要在动画期间访问图层/视图属性的当前值,则可以简单地使用drawRect(_:)
它执行自定义绘图。一切都会正常。
override func drawRect(rect: CGRect) {
}
drawLayer(_:inContext:)
例如,假设您要backgroundColor
在自定义绘图代码中使用:
override func drawRect(rect: CGRect) {
let colorForCustomDrawing = self.layer.backgroundColor
}
在测试代码时,您会注意到 backgroundColor
在动画播放过程中该未返回正确的(即当前)值。而是返回最终值(即动画完成时的值)。
为了在动画过程中获得当前值,您必须访问传递给backgroundColor
的layer
参数drawLayer(_:inContext:)
。而且您还必须吸引context
参数。
知道视图self.layer
和layer
传递给它的参数drawLayer(_:inContext:)
并不总是同一层非常重要!后者可能是前者的副本,并且已经对其属性应用了部分动画。这样,您可以访问飞行中动画的正确属性值。
现在,工程图可以按预期工作:
override func drawLayer(layer: CALayer, inContext context: CGContext) {
let colorForCustomDrawing = layer.backgroundColor
}
但是有两个新问题:setNeedsDisplay()
和一些属性,例如backgroundColor
和opaque
不再对您的视图起作用。UIView
不再转发呼叫并更改到其自己的层。
setNeedsDisplay()
仅在您的视图实现时才做某事 drawRect(_:)
。函数是否实际执行操作并不重要,但UIKit使用它来确定是否执行自定义绘图。
这些属性可能不再起作用,因为 UIView
drawLayer(_:inContext:)
不再调用自己的实现。
因此,解决方案非常简单。只需调用超类的实现drawLayer(_:inContext:)
并实现一个空drawRect(_:)
:
override func drawLayer(layer: CALayer, inContext context: CGContext) {
super.drawLayer(layer, inContext: context)
let colorForCustomDrawing = layer.backgroundColor
}
override func drawRect(rect: CGRect) {
}
概要
使用drawRect(_:)
只要你没有这样的属性在动画过程中返回错误值的问题:
override func drawRect(rect: CGRect) {
}
如果需要动画化视图/图层属性的当前值,请使用drawLayer(_:inContext:)
和 drawRect(_:)
:
override func drawLayer(layer: CALayer, inContext context: CGContext) {
super.drawLayer(layer, inContext: context)
let colorForCustomDrawing = layer.backgroundColor
}
override func drawRect(rect: CGRect) {
}
AccelerometerGraph
。我猜想是在该代码示例中实现的,drawLayer:inContext:
因为除了视图的根层之外,还向该层层次结构添加了一些层,而实际上委托不是UIView
实例。