在图层顶部绘制#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 层次结构是一棵树,其中首先是根层(例如,构成窗口背景的层),然后是其 sublayersCALayer 对象的数组,存储并绘制在以从后到前的顺序),然​​后是它们的子层,以此类推。

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 核心图形?的主要内容,如果未能解决你的问题,请参考以下文章

图层可绘制/图层列表未在彼此之上绘制形状

在 ios 核心图形中绘制电锯

ArcGis10怎么添加一个新的图层

3.PS图层

在图的一侧显示图例 [重复]

如何在将鼠标放在图形元素顶部的画布上添加 JPanel?