UIProgressView with rounded progress track edge - Swift 3

3.7k views Asked by At

I have a UIProgressView and want to have a corner radius for the filled part (progress part) , I am able to make the corners of the progress view rounded using the cornerRadius property , I also want to the filled progress edge to be rounded.Please find below how the progress bar looks now.

enter image description here

I want the edge of the red portion to be rounded.

I tried to set the progressImage with an image having rounded edges , while it solves the issue , the image itself is far stretched , the radii in the corners are not maintained.

The other thing I tried was to draw a rectangle and fill it with the progress color and convert it to a UIImage with the following code and set it as progress Image , in this case , the image is always black , not sure what I am missing. Please find below the code for converting uiview to uiimage

class func imageWithView(view: UIView) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img!
}
2

There are 2 answers

0
Ilyar On

I used this code to filled progress edge to be rounded.

myProgressView.layer.sublayers![1].cornerRadius = 12
myProgressView.subviews[1].clipsToBounds = true
3
Iris On

This question is some months old, but since I had the same doubt, I want to share the answer that I found. I couldn't find a way to do this by just modifying UIProgressView, directly. Seems like the easiest way is to customise a view to look like a progress bar. I based my answer on Umair Afzal's in this question: https://stackoverflow.com/a/41373525/1775356 It's a bit modified for my needs and it is also updated for Swift 3.

import Foundation

import UIKit

class CustomHorizontalProgressView: UIView {
    var color: UIColor = UIColor.red
    var progress: CGFloat = 0.0 {

        didSet {
            setNeedsDisplay()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        setup()
    }

    func setup() {
        self.backgroundColor = color.withAlphaComponent(0.4)
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        var progress = self.progress
        progress = progress > 1.0 ? progress / 100 : progress

        self.layer.cornerRadius = self.frame.height / 2.0

        let margin: CGFloat = 0
        var width = (self.frame.width - margin)  * progress
        let height = self.frame.height - margin

        if (width < height) {
            width = height
        }

        let pathRef = UIBezierPath(roundedRect: CGRect(x: margin / 2.0, y: margin / 2.0, width: width, height: height), cornerRadius: height / 2.0)

        color.setFill()
        pathRef.fill()

        UIColor.clear.setStroke()
        pathRef.stroke()

        pathRef.close()            
    }
}

I'm using a color for the progress tint and the same color with alpha 40% for the background tint. This is easily changeable by selecting another background color. For the record, the outside rounded corners were added in the IB. This can also be done programmatically. It looks like this: