For the initial question have a look at the edit-log of this post.
I mostly used the code from here and am now not sure what to put in outerCircleView(frame: ???):, so that it get's displayed correctly within the constrains I set for outerCirvleView: UIButton.
var circleLayer: CAShapeLayer!
@IBDesignable // enables rendering in StoryBoard
class outerCircleView: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
// Use UIBezierPath as an easy way to create the CGPath for the layer.
// The path should be the entire circle.
let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)
// Setup the CAShapeLayer with the path, colors, and line width
circleLayer = CAShapeLayer()
circleLayer.path = circlePath.CGPath
circleLayer.fillColor = UIColor.clearColor().CGColor
circleLayer.strokeColor = UIColor.redColor().CGColor
circleLayer.lineWidth = 5.0;
// Don't draw the circle initially
circleLayer.strokeEnd = 0.0
// Add the circleLayer to the view's layer's sublayers
layer.addSublayer(circleLayer)
}
required init(coder aDecoder: NSCoder!)
{
super.init(coder: aDecoder)
}
func animateCircle(duration: NSTimeInterval) {
// We want to animate the strokeEnd property of the circleLayer
let animation = CABasicAnimation(keyPath: "strokeEnd")
// Set the animation duration appropriately
animation.duration = duration
// Animate from 0 (no circle) to 1 (full circle)
animation.fromValue = 0
animation.toValue = 1
// Do a linear animation (i.e. the speed of the animation stays the same)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
// Set the circleLayer's strokeEnd property to 1.0 now so that it's the
// right value when the animation ends.
circleLayer.strokeEnd = 1.0
// Do the actual animation
circleLayer.addAnimation(animation, forKey: "animateCircle")
}
}
func addCircleView() {
// Create a new CircleView
var circleView = outerCircleView(frame: ???)
view.addSubview(circleView)
// Animate the drawing of the circle over the course of 1 second
circleView.animateCircle(1.0)
}
The post you link spells out what to in detail.
As explained in that post, you need to not use drawRect. (So the way to adapt your code is to start over with a new approach.) Instead you need to create a CAShapeLayer and install it as a sublayer of your view. You can then use a CABasicAnimation to animate the strokeEnd property of the shape layer.
Nowhere in your edited code do you set the frame of your shape layer.
Add the following code to your layoutSubviews method: (create one if you don't have one already.)
override func layoutSubviews()
{
var frame = self.layer.bounds
circleLayer.frame = frame
}
Leave the code that creates your circlePath in init, since you only want to do that once.
Move the code that creates your circle path into layoutSubviews
. Your view's size often changes after init. layoutSubviews gets called if and when your view's size changes, which is what you want. (When the user rotates their phone your view might change sizes. If that happens layoutSubviews
will be called again, and you will generate a new, correctly sized circle path, which is what you want to do. You want to resize your circle layer and rebuild your circle path each time your view changes size.)