puks1978
puks1978

Reputation: 3697

UIProgressView value under 0.1 not showing correctly

I am not sure (as I couldn't find anything) if this is the way progress views, work but when I have a value under 0.1, let's say 0.05, the progress view always shows up to 0.1, then anything above 0.1 works fine.

Is this normal?

Upvotes: 3

Views: 1955

Answers (2)

Sonastra
Sonastra

Reputation: 189

I experimented a bit with that, and it turns out the minimum width of the progress indicator is twice its height.

As an exemple, say you have a UIProgressView that's 500px long and 50px high, any progress value below 0.2 will actually show a progress indicator that's 100px long. Indeed, 50px * 2 = 100px is the minimum width, for some reason .. So 0.2 * 500px = 100px is the minimum value that can be correctly displayed.

I would also recommend creating a custom progress view since it's quite a trivial component, and that sizing "feature" from Apple seems completely counter-intuitive to me.

I created a simple custom view using auto layout to make it easy to reuse:

class ProgressView: UIView {

    var progress: Float = 0 {
        didSet {
            updateProgressView()
        }
    }

    private let progressView = UIView()
    private var progressViewWidthConstraint: NSLayoutConstraint?

    init() {
        super.init(frame: .zero)

        clipsToBounds = true
        backgroundColor = .lightGray

        addSubview(progressView)

        progressView.translatesAutoresizingMaskIntoConstraints = false
        progressView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        progressView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        progressView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
        progressViewWidthConstraint = progressView.widthAnchor.constraint(equalToConstant: 140)
        progressViewWidthConstraint?.isActive = true
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        updateProgressView()
    }

    func updateProgressView() {
        let isCompleted = progress >= 1.0

        progressView.backgroundColor = isCompleted ? .green : .blue
        progressViewWidthConstraint?.constant = bounds.width * CGFloat(progress)
    }
}

Upvotes: 0

glyvox
glyvox

Reputation: 58069

This is a side effect of using a UIProgressView with a small width. Apple likely made this decision because they want to give clearly visible feedback to users that there is some progress going on - even if the view itself is short.

For a workaround, you can create a custom progress view with two views - one for the bar itself and one for the progress. After that, you can set the width of the progress view to the width of the bar itself, multiplied by the percentage progress.

You can use the cornerRadius property of CALayer for rounded edges.

let barWidth: CGFloat = 240
let barHeight: CGFloat = 2
let progress: CGFloat = 0.23

let progressBarView = UIView(frame: CGRect(x: 0, y: 0, width: barWidth, height: barHeight))
progressBarView.backgroundColor = .lightGray
progressBarView.layer.cornerRadius = barHeight / 2
progressBarView.clipsToBounds = true
view.addSubview(progressBarView)

let progressView = UIView(frame: CGRect(x: 0, y: 0, width: barWidth * progress, height: barHeight))
progressView.backgroundColor = .blue
progressBarView.addSubview(progressView)

Result:

screenshot of the custom progress bar

Upvotes: 1

Related Questions