Reputation: 143
I am trying to draw a circular progress bar using CAShapeLayer inside a custom UIView which has been auto constraint, I don't want to draw my circle in the center of my super view but rather in the center of my custom view because I have other views on top my code below draws a circle but it is not positioned in the specified view
// Custom View
let gaugeViewHolder = UIView()
scrollView.addSubview(gaugeViewHolder)
gaugeViewHolder.translatesAutoresizingMaskIntoConstraints = false
gaugeViewHolder.backgroundColor = UIColor.black
gaugeViewHolder.leadingAnchor.constraint(equalTo: motherView.leadingAnchor).isActive = true
gaugeViewHolder.topAnchor.constraint(equalTo: defaultAccImage.bottomAnchor, constant: 70).isActive = true
gaugeViewHolder.trailingAnchor.constraint(equalTo: motherView.trailingAnchor).isActive = true
gaugeViewHolder.heightAnchor.constraint(equalToConstant: 200).isActive = true
//Now my circle
let shapeLayer = CAShapeLayer()
let centerForGauge = gaugeViewHolder.center
let circularPath = UIBezierPath(arcCenter: centerForGauge
, radius: 80, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.white.withAlphaComponent(0.20).cgColor
shapeLayer.lineWidth = 10
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = kCALineCapRound
gaugeViewHolder.layer.addSublayer(shapeLayer)
Upvotes: 1
Views: 2510
Reputation: 143
let gaugeViewHolder = UIView()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.addSubview(gaugeViewHolder)
gaugeViewHolder.translatesAutoresizingMaskIntoConstraints = false
gaugeViewHolder.backgroundColor = UIColor.black
gaugeViewHolder.leadingAnchor.constraint(equalTo: motherView.leadingAnchor).isActive = true
gaugeViewHolder.topAnchor.constraint(equalTo: defaultAccImage.bottomAnchor, constant: 70).isActive = true
gaugeViewHolder.trailingAnchor.constraint(equalTo: motherView.trailingAnchor).isActive = true
gaugeViewHolder.heightAnchor.constraint(equalToConstant: 200).isActive = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let shapeLayer = CAShapeLayer()
let centerForGauge = gaugeViewHolder.center
print("gauge width:: \(centerForGauge)")
let circularPath = UIBezierPath(arcCenter: CGPoint(x: gaugeViewHolder.frame.size.width/2, y: gaugeViewHolder.frame.size.height/2)
, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.white.withAlphaComponent(0.50).cgColor
shapeLayer.lineWidth = 10
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = kCALineCapRound
gaugeViewHolder.layer.addSublayer(shapeLayer)
}
Upvotes: 1
Reputation: 131511
You never set the frame of the shape layer. It should be the owning view's bounds rect if you want the shape layer to overlay the view's rectangle.
Here is code that adds a shape layer to a view that I added in a sample app storyboard and wired up as an IBOutlet:
@IBOutlet weak var gaugeViewHolder: UIView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
gaugeViewHolder.backgroundColor = UIColor.lightGray
//Now my circle
let shapeLayer = CAShapeLayer()
shapeLayer.borderWidth = 2.0 //Add a box on the shape layer so you can see where it gets drawn.
shapeLayer.frame = gaugeViewHolder.bounds //Use the view's bounds as the layer's frame
//Convert gaugeViewHolder's center from it's superview's coordinate system to it's coordinate system
let centerForGauge = gaugeViewHolder?.superview?.convert(gaugeViewHolder.center, to: gaugeViewHolder) ?? CGPoint.zero
let lineWidth = CGFloat(5.0)
//Use 1/2 the shortest side of the shapeLayer's frame for the radius, inset for the circle path's thickness.
let radius = max(shapeLayer.frame.size.width, shapeLayer.frame.size.height)/2.0 - lineWidth / 2.0
let circularPath = UIBezierPath(arcCenter: centerForGauge
, radius: radius, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = lineWidth
shapeLayer.fillColor = UIColor.yellow.cgColor
shapeLayer.lineCap = .round
gaugeViewHolder.layer.addSublayer(shapeLayer)
}
I changed the colors and alpha around, and added a borderWidth to the shape layer to make everything stand out.
Upvotes: 0
Reputation: 11537
You may consider add the layer later after all constraints has been applied to your view if you don't set frame by yourself at design time. This works as I have tested in an example.
var gaugeViewHolder : UIView!
override func viewDidLoad() {
super.viewDidLoad()
gaugeViewHolder = UIView()
scrollView.addSubview(gaugeViewHolder)
gaugeViewHolder.translatesAutoresizingMaskIntoConstraints = false
gaugeViewHolder.backgroundColor = UIColor.black
gaugeViewHolder.leadingAnchor.constraint(equalTo: motherView.leadingAnchor).isActive = true
gaugeViewHolder.topAnchor.constraint(equalTo: defaultAccImage.bottomAnchor, constant: 70).isActive = true
gaugeViewHolder.trailingAnchor.constraint(equalTo: motherView.trailingAnchor).isActive = true
gaugeViewHolder.heightAnchor.constraint(equalToConstant: 200).isActive = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let shapeLayer = CAShapeLayer()
let centerForGauge = gaugeViewHolder.center
let circularPath = UIBezierPath(arcCenter: centerForGauge
, radius: 80, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.white.withAlphaComponent(0.20).cgColor
shapeLayer.lineWidth = 10
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = CAShapeLayerLineCap.round
gaugeViewHolder.layer.addSublayer(shapeLayer)
}
Upvotes: 0