I created an arbitrary view
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
view.addSubview(middleView)
Then I created a circle using UIBezierPath; however when I set the position to middleView.center, the circle is far off to the bottom of the view. Can you set the position in the center of a subview?
let shapeLayer = CAShapeLayer()
let circlePath = UIBezierPath(
arcCenter: .zero,
radius: 100,
startAngle: CGFloat(0).toRadians(),
endAngle: CGFloat(360).toRadians(),
clockwise: true)
shapeLayer.path = circlePath.cgPath
shapeLayer.strokeColor = UIColor.purple.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.position = middleView.center
middleView.layer.addSublayer(shapeLayer)
How do I center this circle in that view?
You have two problems.
First, you are setting shapeLayer.position = middleView.center
. The center
of a view is is the superview's geometry. In other words, middleView.center
is relative to view
, not to middleView
. But then you're adding shapeLayer
as a sublayer of middleView.layer
, which means shapeLayer
needs a position
that is in middleView
's geometry, not in view
's geometry. You need to set shapeLayer.position
to the center of middleView.bounds
:
shapeLayer.position = CGPoint(x: middleView.bounds.midX, y: middleView.bounds.midY)
Second, you didn't say where you're doing all this. My guess is you're doing it in viewDidLoad
. But that is too early. In viewDidLoad
, the views loaded from the storyboard still have the frames they were given in the storyboard, and haven't been laid out for the current device's screen size yet. So it's a bad idea to look at frame
(or bounds
or center
) in viewDidLoad
if you don't do something to make sure that things will be laid out correctly during the layout phase. Usually you do this by setting the autoresizingMask
or creating constraints. Example:
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)
However, shapeLayer
doesn't belong to a view, so it doesn't have an autoresizingMask
and can't be constrained. You have to lay it out in code. You could do that, but it's better to just use a view to manage the shape layer. That way, you can use autoresizingMask
or constraints to control the layout of the shape, and you can set it up in 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
}
}
Result:
And after rotating to landscape: