Centre Align CAShape layer in a UIView
Asked Answered
T

4

7

The following is a image for which the the code does not align the centre of the UIView , white color.

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];

enter image description here

Topmast answered 4/6, 2016 at 1:4 Comment(0)
C
22

anchorPoint is not for setting the position of CAShapeLayer, use position instead.

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)

Edit

Sorry for such a rough answer before, the code above may not work as you want, here is the correct answer I just come out. A important thing to note is: How you draw the oval path did effect the position of your 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

From Apple Document,

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

In other word, the oval path is drawn from the edge instead of the center, so you must take into accound the radius of the oval you are drawing. In your case, you need to do this:

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

Now we ensure that the center of drawn path is equal to the center of CAShapeLayer. Then we can use position property to move the CAShapeLayer as we want. The image below could help you understand.

enter image description here enter image description here

Comeback answered 4/6, 2016 at 1:52 Comment(1)
This answer worked but I had to add it in viewDidLayoutSubviews and within that method I had to call view.layoutIfNeeded() before adding the above codeBrittain
I
0
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];
Incinerate answered 4/6, 2016 at 4:21 Comment(0)
M
0

For those still have issue with centering this approach worked for me:

1- Set the shape layer frame equal to parent view frame.

shapeLayer.frame = view.frame

2- remove the shape layer position property.

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

3- set x and y value of your bezier path equal to zero.

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

Only these should be enough, get rid of the rest.

======

If that didn't work, then try this one:

@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)

}
Monarchism answered 27/5, 2019 at 14:4 Comment(0)
A
0

I've encounter same case like this. The final resolution is shapeLayer.needsDisplayOnBoundsChange = true and update CAShapeLayer frame in layoutSubviews, CenteredAlignShapeView can adjust when using 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")
    }
    
}
Associate answered 18/8, 2021 at 8:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.