居中对齐 UIView 中的 CAShape 层

Centre Align CAShape layer in a UIView

以下是代码未对齐 UIView 中心的图像,白色。

CAShapeLayer *layer = [CAShapeLayer layer];
layer.anchorPoint=CGPointMake(0.5, 0.5);

layer.path=[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 75.0, 75.0)].CGPath;
layer.fillColor =[UIColor redColor].CGColor;

[self.shapeView.layer addSublayer:layer];

anchorPoint不是用来设置CAShapeLayer的位置,用position代替。

let layer = CAShapeLayer()
layer.borderColor = UIColor.blackColor().CGColor
layer.borderWidth = 100

layer.bounds = CGRectMake(0, 0, 50, 50)
layer.position = myView.center
layer.fillColor = UIColor.redColor().CGColor
view.layer.addSublayer(layer)

编辑

抱歉之前这么粗略的回答,上面的代码可能不能如你所愿,这是我刚出来的正确答案。需要注意的重要一点是:如何绘制椭圆路径确实影响了 CAShapeLayer

的位置
let layer = CAShapeLayer()
myView.layer.addSublayer(layer)
layer.fillColor = UIColor.redColor().CGColor
layer.anchorPoint = CGPointMake(0.5, 0.5)
layer.position = CGPointMake(myView.layer.bounds.midX, myView.layer.bounds.midY)
layer.path = UIBezierPath(ovalInRect: CGRectMake(-75.0 / 2, -75.0 / 2, 75.0, 75.0)).CGPath

来自 Apple 文档,

The oval path is created in a clockwise direction (relative to the default coordinate system)

换句话说,椭圆路径是从边缘而不是中心绘制的,所以你必须考虑你绘制的椭圆的半径。在您的情况下,您需要这样做:

layer.path = UIBezierPath(ovalInRect: CGRectMake(-75.0 / 2, -75.0 / 2, 75.0, 75.0)).CGPath 

现在我们确保绘制路径的中心等于CAShapeLayer的中心。然后我们可以使用 position 属性 来移动 CAShapeLayer 。下图可以帮助你理解。

CAShapeLayer *layer = [CAShapeLayer layer];
layer.anchorPoint=CGPointMake(0.5, 0.5);

layer.path=[UIBezierPath bezierPathWithOvalInRect:CGRectMake((self.shapeView.frame.size.width/2)-37.5, (self.shapeView.frame.size.height/2)-37.5, 75.0, 75.0)].CGPath;
//37.5 means width & height divided by 2
layer.fillColor =[UIColor redColor].CGColor;

[self.shapeView.layer addSublayer:layer];

对于那些仍然对居中有疑问的人,这种方法对我有用:

1- 设置形状图层框架等于父视图框架。

shapeLayer.frame = view.frame

2-去掉形状图层位置属性.

// shapeLayer.position = CGPoint(x: ,y: )

3- 将贝塞尔曲线路径的 x 和 y 值设置为零。

UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: self.width, height: 
self.height))

只有这些就够了,其他的都去掉

======

如果还是不行,试试这个:

@IBDesignable class YourView: UIView {

private var shapeLayer: CAShapeLayer!

override func draw(_ rect: CGRect) {
    self.shapeLayer = CAShapeLayer()
    self.shapeLayer.path = bezierPath.cgPath
    self.shapeLayer.fillColor = UIColor.blue.cgColor

    let bezierPathHeight = self.bezierPath.cgPath.boundingBox.height
    let bezierPathWidth = self.bezierPath.cgPath.boundingBox.width

    self.shapeLayer.setAffineTransform(CGAffineTransform.init(translationX: self.bounds.width / bezierPathWidth, y: self.bounds.height / bezierPathHeight))

    self.shapeLayer.setAffineTransform(CGAffineTransform.init(scaleX: self.bounds.width / bezierPathHeight, y: self.bounds.height / bezierPathHeight))

    self.layer.addSublayer(self.shapeLayer)

}

我遇到过这样的情况。最终分辨率为shapeLayer.needsDisplayOnBoundsChange = true并在layoutSubviews中更新CAShapeLayer frame,CenteredAlignShapeView可以在使用Auto Layout时进行调整。

class CenteredAlignShapeView: UIView {
    
    public let dot = CAShapeLayer()
 
    init() {
        super.init(frame: .zero)
        dot.needsDisplayOnBoundsChange = true
        layer.insertSublayer(dot, at: 0)
        dot.fillColor = UIColor.red.cgColor
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        dot.frame = bounds
        let circlePath = UIBezierPath(arcCenter: CGPoint(x: bounds.width/2, y: bounds.height/2), radius: 4, startAngle: 0, endAngle: CGFloat.pi*2, clockwise: true)
        dot.path = circlePath.cgPath
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}