在子视图中添加相同图层会更改其视觉位置

时间:2018-04-08 10:49:11

标签: ios swift core-animation calayer swift-playground

我在视图中添加了一个子视图(带有黑色边框)并居中。

然后我用CAShapeLayer生成2个相同的三角形,并在子视图中添加一个,在主视图中添加另一个。

以下是Playground中的视觉结果,我们可以看到绿色三角形完全关闭并且应该居中。

Playground result

以下是代码:

let view = UIView()
let borderedView = UIView()
var containedFrame = CGRect(x: 0, y: 0, width: 100, height: 100)

func setupUI() {
    view.frame = CGRect(x: 0, y: 0, width: 300, height: 600)
    view.backgroundColor = .white
    borderedView.frame = containedFrame
    borderedView.center = view.center
    borderedView.backgroundColor = .clear
    borderedView.layer.borderColor = UIColor.black.cgColor
    borderedView.layer.borderWidth = 1
    view.addSubview(borderedView)
    setupTriangles()
}

private func setupTriangles() {
    view.layer.addSublayer(createTriangle(color: .red)) // RED triangle
    borderedView.layer.addSublayer(createTriangle(color: .green)) // GREEN triangle
}

private func createTriangle(color: UIColor) -> CAShapeLayer {
    let layer = CAShapeLayer()
    let bezierPath = UIBezierPath()
    bezierPath.move(to: CGPoint(x: 0, y: 0))
    bezierPath.addLine(to: CGPoint(x: -containedFrame.width, y: 0))
    bezierPath.addLine(to: CGPoint(x: 0, y: -containedFrame.height))
    bezierPath.close()
    layer.position = borderedView.center
    layer.path = bezierPath.cgPath
    layer.fillColor = color.cgColor
    return layer
}

注意:所有position(视图,borderedView和两个三角形)都是相同的(150.0, 300.0)

问题:为什么绿色图层不在正确的位置?

2 个答案:

答案 0 :(得分:3)

@DuncanC是对的,每个视图都有自己的坐标系。你的问题就在这一行:

layer.position = borderedView.center

将图层的位置设置为坐标系view中的borderedView的框架中心。创建绿色三角形时,需要使用borderedView的坐标系。

您可以通过将视图传递到createTriangle函数来解决此问题,然后使用该视图的bounds的中心作为图层位置:

private func setupTriangles() {
    view.layer.addSublayer(createTriangle(color: .red, for: view)) // RED triangle
    borderedView.layer.addSublayer(createTriangle(color: .green, for: borderedView)) // GREEN triangle
}

private func createTriangle(color: UIColor, for view: UIView) -> CAShapeLayer {
    let layer = CAShapeLayer()
    let bezierPath = UIBezierPath()
    bezierPath.move(to: CGPoint(x: 0, y: 0))
    bezierPath.addLine(to: CGPoint(x: -containedFrame.width, y: 0))
    bezierPath.addLine(to: CGPoint(x: 0, y: -containedFrame.height))
    bezierPath.close()
    layer.position = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
    layer.path = bezierPath.cgPath
    layer.fillColor = color.cgColor
    return layer
}

注意:执行此操作时,绿色三角形会直接显示在红色三角形下方,因此不可见。

答案 1 :(得分:2)

每个视图/图层都使用它的superview / superlayer的坐标系。如果向self.view.layer添加图层,它将位于self.view.layer的坐标系中。如果向borderedView.layer添加图层,它将位于borderedView.layer的坐标系中。

将视图/图层层次结构视为图纸的堆栈。您在当前棋子的坐标系中的当前棋子(超视图/图层)上放置了一张新纸,但是如果您在新视图/图层上绘图,或在该视图/图层中添加新视图/图层,你使用新的视图/图层的坐标系。