Swift CAShapeLayer形状可以在子视图中居中吗?

Swift CAShapeLayer形状可以在子视图中居中吗?,swift,cashapelayer,caanimation,Swift,Cashapelayer,Caanimation,我创建了一个任意视图 让middleView=UIView( 帧:CGRect(x:0.0, y:view.frame.height/4, 宽度:view.frame.width, 高度:视图。框架。高度/4) middleView.backgroundColor=UIColor.blue view.addSubview(middleView) 然后我用UIBezierPath创建了一个圆;但是,当我将位置设置为middleView.center时,圆圈远离视图底部。可以设置子视图中心的位置吗

我创建了一个任意视图

让middleView=UIView(
帧:CGRect(x:0.0,
y:view.frame.height/4,
宽度:view.frame.width,
高度:视图。框架。高度/4)
middleView.backgroundColor=UIColor.blue
view.addSubview(middleView)
然后我用UIBezierPath创建了一个圆;但是,当我将位置设置为middleView.center时,圆圈远离视图底部。可以设置子视图中心的位置吗

let shapeLayer=CAShapeLayer()
设circlePath=UIBezierPath(
弧中心:。零,
半径:100,
startAngle:CGFloat(0).toRadians(),
端角:CGFloat(360).toRadians(),
顺时针:正确)
shapeLayer.path=circlePath.cgPath
shapeLayer.strokeColor=UIColor.purple.cgColor
shapeLayer.fillColor=UIColor.clear.cgColor
shapeLayer.position=middleView.center
middleView.layer.addSublayer(shapeLayer)
如何在该视图中使该圆居中?

您有两个问题

首先,您要设置
shapeLayer.position=middleView.center
。视图的
中心是superview的几何体。换句话说,
middleView.center
是相对于
view
,而不是相对于
middleView
。但随后您将
shapeLayer
添加为
middleView.layer
的子层,这意味着
shapeLayer
需要一个
位置,该位置位于
middleView
的几何体中,而不是
视图的几何体中。您需要将
shapeLayer.position
设置为
middleView.bounds的中心:

shapeLayer.position = CGPoint(x: middleView.bounds.midX, y: middleView.bounds.midY)
第二,你没有说你在哪里做这些。我猜你是在
viewDidLoad
中完成的。但这还为时过早。在
viewDidLoad
中,从故事板加载的视图仍然具有故事板中给出的帧,并且尚未针对当前设备的屏幕大小进行布局。因此,如果在布局阶段没有采取措施确保正确布局,那么在
viewdiload
中查看
frame
(或
bounds
center
)是个坏主意。通常,您可以通过设置
自动调整大小任务
或创建约束来实现这一点。例如:

let middleView = UIView(
    frame: CGRect(x: 0.0,
                  y: view.frame.height/4,
                  width: view.frame.width,
                  height: view.frame.height/4))
middleView.backgroundColor = UIColor.blue
middleView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleBottomMargin]
view.addSubview(middleView)
但是,
shapeLayer
不属于视图,因此它没有
autoresizingMask
,并且不能被约束。你必须用代码来描述它。可以这样做,但最好只使用视图来管理形状层。这样,您可以使用
autoresizingMask
或约束来控制形状的布局,并且可以在
viewDidLoad
中进行设置

    let circleView = CircleView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    circleView.center = CGPoint(x: middleView.bounds.midX, y: middleView.bounds.midY)
    circleView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
    circleView.shapeLayer.strokeColor = UIColor.purple.cgColor
    circleView.shapeLayer.fillColor = nil
    middleView.addSubview(circleView)

...

class CircleView: UIView {
    override class var layerClass: AnyClass { return CAShapeLayer.self }

    var shapeLayer: CAShapeLayer { return layer as! CAShapeLayer }

    override func layoutSubviews() {
        super.layoutSubviews()
        shapeLayer.path = UIBezierPath(ovalIn: bounds).cgPath
    }

}
结果:

旋转到横向后:

您有两个问题

首先,您要设置
shapeLayer.position=middleView.center
。视图的
中心是superview的几何体。换句话说,
middleView.center
是相对于
view
,而不是相对于
middleView
。但随后您将
shapeLayer
添加为
middleView.layer
的子层,这意味着
shapeLayer
需要一个
位置,该位置位于
middleView
的几何体中,而不是
视图的几何体中。您需要将
shapeLayer.position
设置为
middleView.bounds的中心:

shapeLayer.position = CGPoint(x: middleView.bounds.midX, y: middleView.bounds.midY)
第二,你没有说你在哪里做这些。我猜你是在
viewDidLoad
中完成的。但这还为时过早。在
viewDidLoad
中,从故事板加载的视图仍然具有故事板中给出的帧,并且尚未针对当前设备的屏幕大小进行布局。因此,如果在布局阶段没有采取措施确保正确布局,那么在
viewdiload
中查看
frame
(或
bounds
center
)是个坏主意。通常,您可以通过设置
自动调整大小任务
或创建约束来实现这一点。例如:

let middleView = UIView(
    frame: CGRect(x: 0.0,
                  y: view.frame.height/4,
                  width: view.frame.width,
                  height: view.frame.height/4))
middleView.backgroundColor = UIColor.blue
middleView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleBottomMargin]
view.addSubview(middleView)
但是,
shapeLayer
不属于视图,因此它没有
autoresizingMask
,并且不能被约束。你必须用代码来描述它。可以这样做,但最好只使用视图来管理形状层。这样,您可以使用
autoresizingMask
或约束来控制形状的布局,并且可以在
viewDidLoad
中进行设置

    let circleView = CircleView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    circleView.center = CGPoint(x: middleView.bounds.midX, y: middleView.bounds.midY)
    circleView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
    circleView.shapeLayer.strokeColor = UIColor.purple.cgColor
    circleView.shapeLayer.fillColor = nil
    middleView.addSubview(circleView)

...

class CircleView: UIView {
    override class var layerClass: AnyClass { return CAShapeLayer.self }

    var shapeLayer: CAShapeLayer { return layer as! CAShapeLayer }

    override func layoutSubviews() {
        super.layoutSubviews()
        shapeLayer.path = UIBezierPath(ovalIn: bounds).cgPath
    }

}
结果:

旋转到横向后:


谢谢!这是非常有见地的。一个问题:我可以为自动布局约束切换出
circleView.autoresizingMask=[…]
?它们执行相同的任务吗?是的,如果您记得设置
circleView.translatesAutoResizezingMacSkinToConstraints=false
,您可以使用约束来布局
circleView
,我很困惑
CGRect.x
CGRect.y
中的
0
是如何允许圆居中的,这并不重要,因为我在下一行设置了
circleView.center
。谢谢!这是非常有见地的。一个问题:我可以为自动布局约束切换出
circleView.autoresizingMask=[…]
?它们执行相同的任务吗?是的,如果您记得设置
circleView.translatesAutoResizezingMacSkinToConstraints=false
,您可以使用约束来布局
circleView
,我很困惑
CGRect.x
CGRect.y
中的
0
是如何允许圆居中的,这并不重要,因为我在下一行设置了
circleView.center