I am using a CAShapeLayer with UIBezierPath to make a circular progress bar. The code requires a center value based on a CGPoint.
let circleLayer = CAShapeLayer()
let circlePath = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
I have set the value manually as follows:
let center = CGPoint(x: 70, y: 70)
However those values are relative to the superView and I need to make it relative to its parent UIView.
All other elements in the UIView are constrained using programmatic UI code like this:
sampleText.translatesAutoresizingMaskIntoConstraints = false
sampleText.topAnchor.constraint(equalTo: directionsTitle.bottomAnchor, constant: 0).isActive = true
sampleText.leadingAnchor.constraint(equalTo: timerFooter.leadingAnchor, constant: 8).isActive = true
sampleText.trailingAnchor.constraint(equalTo: timerFooter.trailingAnchor, constant: -8).isActive = true
Fixed values may work fine on one device but will be out of alignment on a larger or smaller device. My question is, how do I determine the values for center of the UIView that will meet the values required of CGPoint?
I have tried this:
let centerX = view.centerXAnchor
let centerY = view.centerYAnchor
let center = CGPoint(x: centerX, y: centerY)
However, that throws an error: No exact matches in call to initializer
The following image reflects where the shape placement is relative to. The blue box indicates the desired UIView area where I want to position the circle.
Advice from wiser minds would be greatly appreciated.
CodePudding user response:
Ah, ok, I think I understand what the problem is that you're facing.
I think your issue is that you're trying to use the CAShapeLayer
like it is a UIView. When in reality they don't behave like that at all.
What you should be doing is creating a UIView subclass and putting the CAShapeLayer
in there. Now you only need to worry about how the CAShapeLayer
fits into its own UIView subclass.
To "position the layer" into some other view you actually don't need to worry about that at all. You just place the new UIView subclass and the layer will go along with it.
e.g.
class MyProgressView: UIView {
let circleLayer: CAShapeLayer
// add the circleLayer
// add properties for customising the circle layer
// Position the circle layer in the centre of the MyProgressView frame
// I'd suggest using `layoutSubviews` or something for this.
// etc...
}
Now... to position your "CircleLayer" you actually don't need to. You just position the MyProgressView
where you want it to be and the layer is part of that so will go along for the ride.
From your screenshot it looks like you want the view with the blue rectangle to contain the circleLayer. If that is the case then make the blue rectangle view your custom UIView subclass and ... done. It will now contain the circle view.
RayWenderlich has some good stuff about customising views with CALayer... https://www.raywenderlich.com/10317653-calayer-tutorial-for-ios-getting-started#toc-anchor-002
CodePudding user response:
It sounds like you want the midpoint of the UIView's bounds
I think that's yourView.bounds.midX
and yourView.bounds.midY
A view's bounds
is its own coordinate space. A view's frame
is its location in its parent space.
UIView
has methods like convertPoint:toCoordinateSpace:
and friends for converting points and rects between those spaces.