在图层顶部绘制#rect 核心图形?
Posted
技术标签:
【中文标题】在图层顶部绘制#rect 核心图形?【英文标题】:draw#rect core graphics, on top of a layer? 【发布时间】:2019-08-05 19:20:55 【问题描述】:假设你在 UIView 中有这个,
override func draw(_ rect: CGRect)
let c = UIGraphicsGetCurrentContext()
c?.setLineWidth(10.0)
c?.move(to: CGPoint(x: 10.0, y: 10.0))
c?.addLine(to: CGPoint(x: 40.0, y: 40.0))
... lots of complicated drawing here, sundry paths, colors, widths etc ...
c?.strokePath()
当然,它会为你画出地狱般的画面。
但是说在同一个 UIView 中你这样做......
func setup() // in inits, layout
if nil etc
thingLayer = CAShapeLayer()
self.layer.insertSublayer(thingLayer, at: 0)
thingLayer.fillColor = UIColor.yellow.cgColor
thingLayer.frame = bounds
let path = ... some fancy path
thingLayer.path = path.cgPath
确实,新的黄色层被绘制在 draw#rect 中的绘图上。
您如何绘制 - 使用核心图形命令 - 在 thingLayer 上,或者最重要的是在另一层上??
核心图形命令:
let c = UIGraphicsGetCurrentContext()
c?.setLineWidth(10.0)
c?.move(to: CGPoint(x: 10.0, y: 10.0))
c?.addLine(to: CGPoint(x: 40.0, y: 40.0))
c?.strokePath()
似乎画到了.layer
主要上方或上方的某个地方
(就我所见,似乎是这样。)
您如何绘制 - 使用核心图形命令 - 在 thingLayer 上,或者最重要的是在另一层上??
在 draw#rect 中你可以指定绘制到哪个 cgLayer 吗?
在 draw#rect 中,你可以制作另一个 cgLayer 并根据上下文绘制那个 cgLayer 吗?
【问题讨论】:
顺便说一句,如果您根据bounds
做任何事情,您需要将其移至layoutSubviews
。
我不确定您是否注意到,我为每个 QA 都添加了赏金。 “一个或多个答案堪称典范,值得额外赏金。”此外,我发现它通常会带来更多的兴趣和其他有价值的想法、答案或 cmets。再次感谢!
【参考方案1】:
底线,draw(_:)
用于渲染UIView
子类的根视图。如果您添加子层,它们将在根视图的draw(_:)
中完成的任何操作之上呈现。
如果您当前在 draw(_:)
中执行了几条路径,您希望在添加的子层之上呈现这些路径,您有以下几种选择:
将要描边的路径移动到它们自己的CAShapeLayer
实例中,并将它们添加到您已经添加的另一个子层之上。
将主 UIView
子类视为容器/内容视图,并添加您自己的私有 UIView
子视图(可能使用“复杂的”draw(_:)
方法)。如果您不想公开这些私有子视图,则不必公开。
将复杂的绘图移动到CALayer
子类的draw(in:)
,然后再次将此子层添加到您已经创建的现有子层之上。
鉴于thingLayer
实际上只设置背景颜色,您可以只设置视图的背景颜色,而根本不使用该背景颜色的图层。
【讨论】:
"用于渲染 UIView 子类的根视图" - 啊哈哈哈哈。 (所以,根 cgLayer,对吗?哪个在根 .layer 上) 在某种意义上@Rob item 3 是“问题的答案”。如果您真的想使用 draw#rect 直接命令,在另一层上,您似乎必须子类化一个层并使用 draw#in。用户 Alexander 在评论中也提到了这一点。 @Fattie 为什么是的,我确实说过。不知何故,我们的 cmets 和东西已被删除。那是怎么回事?【参考方案2】:CALayer
层次结构是一棵树,其中首先是根层(例如,构成窗口背景的层),然后是其 sublayers
(CALayer
对象的数组,存储并绘制在以从后到前的顺序),然后是它们的子层,以此类推。
UIView.draw(_ rect: CGRect)
的实现定义了视图主层 (self.layer
) 的绘制方式。
通过将CAShapeLayer
添加为self.layer
的子层,您可以将其绘制在之后 self.layer
,其效果是将其绘制在上方 em> self.layer
,其中包含您在UIView.draw(_ rect: CGRect)
中绘制的线。
要解决这个问题,您需要将您的笔划放在子层之后您的thingLayer
。
self.layer.insertSublayer(thingLayer, at: 0)
self.layer.insertSublayer(lineLayer, above: thingLayer)
顺便说一句,你忘了委托给super.draw(rect)
。 UIView
的直接子类不是必需的(因为基本实现不做任何事情),但对于其他所有情况都是必需的,并且通常是一个好习惯(以免遇到真正晦涩/令人沮丧的绘图错误)。
【讨论】:
【参考方案3】:如果您的黄色形状层不改变或独立移动,您可以摆脱 CAShapeLayer 并在draw(_:)
的实现顶部自己绘制形状:
let path = // your fancy UIBezierPath
UIColor.yellow.setFill()
path.fill()
否则,正如其他评论者所说,您需要将绘图代码移动到 UIView 或 CALayer 的其他自定义子类中,并按您想要的顺序堆叠它们。
【讨论】:
Robin,确实如此:但总的来说,将计算中的内容分开是件好事。举个例子,我们可能会以一种或另一种方式对一些有问题的图层进行动画处理;在这种情况下,拥有不同的层真的很明智/更容易。以上是关于在图层顶部绘制#rect 核心图形?的主要内容,如果未能解决你的问题,请参考以下文章