如何在父 CALayer 中居中 CALayer
How to center CALayers inside parent CALayer
我有一个 UIBezierPaths 数组,我正在循环创建一个 CALayer。生成 CALayer 的代码如下所示:
let layer = CAShapeLayer()
layer.path = path.cgPath
layer.strokeColor = UIColor.gray.cgColor
layer.fillColor = UIColor.clear.cgColor
layer.lineWidth = 3
layer.lineJoin = .bevel
return layer
返回每一层后,我将其添加到更大的层 (shapeLayer
),然后将其添加到 UIView
层。 (希望这是有道理的)。
我遇到的问题是将循环时添加的子层(在 finalShape 内)居中。他们显然使用 path.cgPath
设置了特定的路径,我不知道如何在保持他们的位置的同时实现这一点。我真的(显然)对 CALayers 了解不够,无法解决这个问题,我们将不胜感激。
谢谢。
-- 如果我向您展示整个代码可能会更有帮助
private let shapeLayer = CALayer()
func bind(shape: Shape) {
let data = NSKeyedUnarchiver.unarchiveObject(with: shape.strokeData)
guard let paths = data as? [UIBezierPath] else { return }
for path in paths {
let guideLine = drawPathLayer(for: path)
shapeLayer.addSublayer(guideLine)
}
layer.addSublayer(shapeLayer)
}
private func drawPathLayer(for path: UIBezierPath) -> CALayer {
let layer = CAShapeLayer()
layer.path = path.cgPath
layer.strokeColor = UIColor.gray.cgColor
layer.fillColor = UIColor.clear.cgColor
layer.lineWidth = 3
layer.lineJoin = .bevel
return layer
}
如果要定位图层(或视图),执行此操作的时间点至关重要。例如,如果您在 viewDidLoad
中执行此操作,则为时过早,因为父层还没有最终大小。此外,父层的大小可能会发生变化,因此最好在父层的框架发生变化时将子层居中。您可以使用 CALayer
的子 class 并覆盖 layoutSublayers
.
它看起来像这样(不是一个运行例子):
class CenteringLayer: CALayer {
override func layoutSublayers() {
super.layoutSublayers()
if let theSublayers = sublayers {
for s in theSublayers {
var theFrame = s.frame
theFrame.origin.x = (bounds.width - theFrame.width) / 2.0
theFrame.origin.y = (bounds.height - theFrame.height) / 2.0
s.frame = theFrame
}
}
}
}
注意:您的 layer
还必须通过
布局 shapeLayer
shapeLayer.frame = layer.bounds
使这项工作。您可以通过为 layer
创建另一个 CALayer
的子 class 并覆盖 layoutSublayers()
或(如果 layer
是视图层)覆盖来实现layoutSubviews()
在您看来class。第三个选项可能是在视图 class 中覆盖 layoutSublayers(of:)
,因为 UIView 始终是其层的委托。
但是这些方法有点不优雅,所以你最好考虑减少代码中的层数。例如你应该尽量避免shapeLayer
。
如果所有路径都具有相同的属性,您可能只使用一个 CAShapeLayer
与串联路径,因为图层可能非常耗费资源。
我有一个 UIBezierPaths 数组,我正在循环创建一个 CALayer。生成 CALayer 的代码如下所示:
let layer = CAShapeLayer()
layer.path = path.cgPath
layer.strokeColor = UIColor.gray.cgColor
layer.fillColor = UIColor.clear.cgColor
layer.lineWidth = 3
layer.lineJoin = .bevel
return layer
返回每一层后,我将其添加到更大的层 (shapeLayer
),然后将其添加到 UIView
层。 (希望这是有道理的)。
我遇到的问题是将循环时添加的子层(在 finalShape 内)居中。他们显然使用 path.cgPath
设置了特定的路径,我不知道如何在保持他们的位置的同时实现这一点。我真的(显然)对 CALayers 了解不够,无法解决这个问题,我们将不胜感激。
谢谢。
-- 如果我向您展示整个代码可能会更有帮助
private let shapeLayer = CALayer()
func bind(shape: Shape) {
let data = NSKeyedUnarchiver.unarchiveObject(with: shape.strokeData)
guard let paths = data as? [UIBezierPath] else { return }
for path in paths {
let guideLine = drawPathLayer(for: path)
shapeLayer.addSublayer(guideLine)
}
layer.addSublayer(shapeLayer)
}
private func drawPathLayer(for path: UIBezierPath) -> CALayer {
let layer = CAShapeLayer()
layer.path = path.cgPath
layer.strokeColor = UIColor.gray.cgColor
layer.fillColor = UIColor.clear.cgColor
layer.lineWidth = 3
layer.lineJoin = .bevel
return layer
}
如果要定位图层(或视图),执行此操作的时间点至关重要。例如,如果您在 viewDidLoad
中执行此操作,则为时过早,因为父层还没有最终大小。此外,父层的大小可能会发生变化,因此最好在父层的框架发生变化时将子层居中。您可以使用 CALayer
的子 class 并覆盖 layoutSublayers
.
它看起来像这样(不是一个运行例子):
class CenteringLayer: CALayer {
override func layoutSublayers() {
super.layoutSublayers()
if let theSublayers = sublayers {
for s in theSublayers {
var theFrame = s.frame
theFrame.origin.x = (bounds.width - theFrame.width) / 2.0
theFrame.origin.y = (bounds.height - theFrame.height) / 2.0
s.frame = theFrame
}
}
}
}
注意:您的 layer
还必须通过
shapeLayer
shapeLayer.frame = layer.bounds
使这项工作。您可以通过为 layer
创建另一个 CALayer
的子 class 并覆盖 layoutSublayers()
或(如果 layer
是视图层)覆盖来实现layoutSubviews()
在您看来class。第三个选项可能是在视图 class 中覆盖 layoutSublayers(of:)
,因为 UIView 始终是其层的委托。
但是这些方法有点不优雅,所以你最好考虑减少代码中的层数。例如你应该尽量避免shapeLayer
。
如果所有路径都具有相同的属性,您可能只使用一个 CAShapeLayer
与串联路径,因为图层可能非常耗费资源。