42

I've been trying to change the size and rotation of a progress view to adopt the size of the screen. It would basically function have a filling glass effect on the screen of the phone.

I rotated it fairly harmlessly by using self.masteryProgress.transform = CGAffineTransformMakeRotation((CGFloat(-90) / CGFloat(180.0) * CGFloat(M_PI)))

I got the size of the view encasing the screen using view.bounds trying to get the rect and the width x height. So I'm not stuck there.

I tried using .frame .drawRect but when I use those it either breaks them or does nothing.

The height attribute seems to be locked at a constant value of 2 in interfaceBuilder.

Any solutions before I build a custom animation?

I tried setting the height of the progress bar in interfaceBuilder like some other posts said, but I need to have the progress view fill the whole screen no matter what device it's running on so that solution won't work in my case.

I ended up using CGAffineTransformScale(masteryProgress.transform, view.bounds.height / 1334, (view.bounds.width / 2))

Since I'm rotating the progressView vertically, I set the progress view to a width of 1334 (the height of the iPhone 6 Plus) and a height of 2. By dividing the height of the screen by these values it should resize to any phone perfectly.

Zach Morris
  • 367
  • 1
  • 4
  • 12
  • possible duplicate of [Progress view height in iOS 7](http://stackoverflow.com/questions/18717895/progress-view-height-in-ios-7) – Wonjung Kim Jul 07 '15 at 06:24
  • Plesae check the previous question. The autolayout way can be also applied in storyboard. – Wonjung Kim Jul 07 '15 at 06:26
  • @WonjugKim That's good and all, but I need it to resize to the size of the screen and interface builder only lets you resize statically. – Zach Morris Jul 07 '15 at 15:44

13 Answers13

103

You can scale it by set its transform like so:

Swift 2

masteryProgress.transform = CGAffineTransformScale(masteryProgress.transform, 1, 20)

Swift 3、4

masteryProgress.transform = masteryProgress.transform.scaledBy(x: 1, y: 20)

enter image description here

Bannings
  • 10,376
  • 7
  • 44
  • 54
53

I faced problem while making the UIProgressView as round rect one. While using only the transform

masteryProgress.transform = CGAffineTransformMakeScale(1, 4)

I achieved which was not my final requirement.

enter image description here

while my final expectation was something like the following

enter image description here

I finally achieved it by following two steps

1. Set Height Constraint from Interface Builder:

enter image description here

2. Create a custom class of UIProgressView and override func layoutSubviews() to add a custom mask layer:

    override func layoutSubviews() {
        super.layoutSubviews()

        let maskLayerPath = UIBezierPath(roundedRect: bounds, cornerRadius: 4.0)
        let maskLayer = CAShapeLayer()
        maskLayer.frame = self.bounds
        maskLayer.path = maskLayerPath.cgPath
        layer.mask = maskLayer
    }

And here is the final result

enter image description here

Sauvik Dolui
  • 5,520
  • 3
  • 34
  • 44
27

Transform still seems to be the only way to accomplish this. Try adding it as an extension to UIProgressView like so.

extension UIProgressView {

    @IBInspectable var barHeight : CGFloat {
        get {
            return transform.d * 2.0
        }
        set {
            // 2.0 Refers to the default height of 2
            let heightScale = newValue / 2.0
            let c = center
            transform = CGAffineTransformMakeScale(1.0, heightScale)
            center = c
        }
    }   
}
THISguy
  • 371
  • 3
  • 4
20

If you added UIProgressView using Interface Builder, just create height constraint and change to value what you need. That's it.

Stanislau Baranouski
  • 1,425
  • 1
  • 18
  • 22
  • 3
    Oh wow, so right. I was fighting with transforms and disappearing round corners, but actually that was quite simple ;) Only a pity that the storyboard doesn't reflect reality. – Benjamin Piette Mar 13 '18 at 10:03
7

This will work:

masteryProgress.transform = CGAffineTransformMakeScale(1, 4)
Andy Lebowitz
  • 1,471
  • 2
  • 16
  • 23
6

Some modification of 'Sauvik Dolui' answer:

In UIBezierPath you should set cornerRadius: like (self.frame.height / 2). This is more universal solution than use (4.0).

override func layoutSubviews() {
    super.layoutSubviews()

    let maskLayerPath = UIBezierPath(roundedRect: bounds, cornerRadius: self.frame.height / 2)
    let maskLayer = CAShapeLayer()
    maskLayer.frame = self.bounds
    maskLayer.path = maskLayerPath.cgPath
    layer.mask = maskLayer
}
schornon
  • 342
  • 3
  • 4
4

In Swift 3, it's changed to CGAffineTransform(scaleX: CGFloat, y: CGFloat). So code would be:

masteryProgress.transform = CGAffineTransform(scaleX: 1, y: 4)
Pandurang Yachwad
  • 1,695
  • 1
  • 19
  • 29
  • hi ! ... when i use CGAffineTransform for progressview and turn iphone in landscape mode , the progressview-bar reset the scale.. why?! – mrk182 Sep 11 '17 at 22:26
3

In Swift version 3.0.2 use this:

masteryProgress.transform = masteryProgress.transform.scaledBy(x: 1, y: 5)
Prasad Khode
  • 6,602
  • 11
  • 44
  • 59
1

I'm experiencing same with Swift - UIProgressView fills diagonally

After scale progressbar with

CGAffineTransformMakeScale(1.0, 5.0)

bar animation becomes filling from left top corner to right bottom.

Community
  • 1
  • 1
Nevermore
  • 237
  • 2
  • 14
1

Putting the UIProgressView inside a UIStackView and setting the UIStackView's constraints might work as well. At least worked for me

Anestis S.
  • 45
  • 7
0

I tried the accepted answer for Swift 5, had a label pinned to the bottom of the progressView and the label was oddly stretched. To change the height without any other issues I used it's heightAnchor to set it to the height I wanted.

1- create a programmatic UIProgressView:

lazy var progressView: UIProgressView = {
    let progressView = UIProgressView(progressViewStyle: .default)
    progressView.translatesAutoresizingMaskIntoConstraints = false
    progressView.trackTintColor = .white
    progressView.progressTintColor = .green
    progressView.progress = 0
    return progressView
}()

2- set the heightAnchor constraint:

progressView.heightAnchor.constraint(equalToConstant: 12).isActive = true 

progressView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
progressView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
progressView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20).isActive = true
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
0

It works for me:

progress.transform = progress.transform.scaledBy(x: 1, y: self.bounds.size.height)

"self.bounds.size.height" is the height you want

James Ryan
  • 61
  • 1
0

I gave it height constraint and it worked for me. I gave it 10 Constant. But if you are creating a universal app you can also use multipliers.

Simran Singh
  • 445
  • 6
  • 8