George
George

Reputation: 30401

Creating a progress indicator with a rounded rectangle

I am attempting to create a rounded-rectangle progress indicator in my app. I have previously implemented a circular indicator, but not like this shape. I would like it to look something like this (start point is at the top):

enter image description here

But I get this with 0 as the .strokeStart property of the layer:

enter image description here

My current code place in viewDidLoad():

let queueShapeLayer = CAShapeLayer()
let queuePath = UIBezierPath(roundedRect: addToQueue.frame, cornerRadius: addToQueue.layer.cornerRadius)
queueShapeLayer.path = queuePath.cgPath
queueShapeLayer.lineWidth = 5
queueShapeLayer.strokeColor = UIColor.white.cgColor
queueShapeLayer.fillColor = UIColor.clear.cgColor
queueShapeLayer.strokeStart = 0
queueShapeLayer.strokeEnd = 0.5
view.layer.addSublayer(queueShapeLayer)

addToQueue is the button which says 'Upvote'.

Unlike creating a circular progress indicator, I cannot set the start and end angle in the initialisation of a Bezier path.

How do I make the progress start from the top middle as seen in the first image?

Edit - added a picture without corner radius on:

enter image description here

It seems that the corner radius is creating the issue.


If you have any questions, please ask!

Upvotes: 1

Views: 1093

Answers (1)

George
George

Reputation: 30401

I found a solution so the loading indicator works for round corners:

enter image description here

let queueShapeLayer = CAShapeLayer()

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Queue timer
    let radius = addToQueue.layer.cornerRadius
    let diameter = radius * 2
    let totalLength = (addToQueue.frame.width - diameter) * 2 + (CGFloat.pi * diameter)

    let queuePath = UIBezierPath(roundedRect: addToQueue.frame, cornerRadius: radius)
    queueShapeLayer.path = queuePath.cgPath
    queueShapeLayer.lineWidth = 5
    queueShapeLayer.strokeColor = UIColor.white.cgColor
    queueShapeLayer.fillColor = UIColor.clear.cgColor
    queueShapeLayer.strokeStart = 0.25 - CGFloat.pi * diameter / 3 / totalLength // Change the '0.25' to 0.5, 0.75 etc. wherever you want the bar to start
    queueShapeLayer.strokeEnd = queueShapeLayer.strokeStart + 0.5 // Change this to the value you want it to go to (in this case 0.5 or 50% loaded)
    view.layer.addSublayer(queueShapeLayer)
}

After I had did this though, I was having problems that I couldn't animate the whole way round. To get around this, I created a second animation (setting strokeStart to 0) and then I placed completion blocks so I could trigger the animations at the correct time.

Tip:

Add animation.fillMode = CAMediaTimingFillMode.forwards & animation.isRemovedOnCompletion = false when using a CABasicAnimation for the animation to wait until you remove it.

I hope this formula helps anyone in the future!

If you need help, you can always message me and I am willing to help. :)

Upvotes: 2

Related Questions