在子视图中添加相同的图层会改变其视觉位置
Adding the same layer in a subview changes its visual position
我在视图中添加了一个子视图(带有黑色边框)并将其居中。
然后我用 CAShapeLayer 生成 2 个相同的三角形,并将一个添加到子视图,另一个添加到主视图。
这是 Playground 中的视觉结果,我们可以看到绿色三角形完全消失,应该居中。
这是代码:
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)
问题:为什么绿色图层位置不对?
每个view/layer都使用它的superview/superlayer坐标系。如果您向 self.view.layer 添加图层,它将位于 self.view.layer 的坐标系中。如果您向 borderedView.layer 添加图层,它将位于 borderedView.layer 的坐标系中。
将 view/layer 层次结构想象成一堆方格纸。你在当前棋子的坐标系中在当前棋子上放置一张新纸(超级view/layer),但是如果你在新的view/layer上绘制,或者在里面添加新的views/layer那个,你使用新的 view/layer 坐标系。
@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
}
注意:执行此操作时,绿色三角形直接出现在红色三角形下方,因此不可见。
我在视图中添加了一个子视图(带有黑色边框)并将其居中。
然后我用 CAShapeLayer 生成 2 个相同的三角形,并将一个添加到子视图,另一个添加到主视图。
这是 Playground 中的视觉结果,我们可以看到绿色三角形完全消失,应该居中。
这是代码:
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)
问题:为什么绿色图层位置不对?
每个view/layer都使用它的superview/superlayer坐标系。如果您向 self.view.layer 添加图层,它将位于 self.view.layer 的坐标系中。如果您向 borderedView.layer 添加图层,它将位于 borderedView.layer 的坐标系中。
将 view/layer 层次结构想象成一堆方格纸。你在当前棋子的坐标系中在当前棋子上放置一张新纸(超级view/layer),但是如果你在新的view/layer上绘制,或者在里面添加新的views/layer那个,你使用新的 view/layer 坐标系。
@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
}
注意:执行此操作时,绿色三角形直接出现在红色三角形下方,因此不可见。