30

I am experimenting with some new properties in iOS 5 regarding UIProgressView. They are:

@property(nonatomic, retain) UIImage *progressImage;
@property(nonatomic, retain) UIImage *trackImage;

These new properties enable the customisation of the "progress" and the "track" image, so that you can make fancy progress bars without having to roll-your-own.

I however cannot understand how Apple "stretches" the progress images, because documentation is a little flakey / OR there is some standard I am not aware of. Regardless, I am asking if someone can help me understand how to make appropriate progress and tracking images.

I get results like this when I load my custom images, no matter which sizes I try:

Progress Example

My measurements are as follows:

  • UIProgressView length: 226 units
  • trackingImage.png: 10px
  • progressImage.png: 7px

Lastly, here are my custom images:

The Progress Image progressImage.png

The Tracking Image trackImage.png

Sean
  • 5,233
  • 5
  • 22
  • 26

1 Answers1

111

Here's what's going on:

The images you provide to the UIProgressView are basically being shoved in to UIImageViews, and the UIImageView is stretching the image to fill the space.

If you simply do:

[progressView setTrackImage:[UIImage imageNamed:@"track.png"]];

Then you're going to get weird results, because it's trying to stretch a 10px wide image to fill (for example) a 100px wide image view. This means (roughly) that every pixel in the image will be repeated 10 times. So if the pixels in our image were:

0123456789

Then putting that image straight into a 100px wide image view would stretch it something like this:

000000000011111111112222222222333333333344444444445555555555...

This is what's happening to you.

What you really want to have happen is this:

01234567812345678123456781234567812345678...123456789

In other words, you want the image to have a 1 point left edge that is never stretched, the center to be tiled, and to have a 1 point right edge that is also never stretched. To do this, you'll need to make the image resizable:

UIImage *track = [[UIImage imageNamed:@"track"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 1, 0, 1)];
[progressView setTrackImage:track];

If you want this to tile appropriately vertically as well, then the edge insets should be {1, 1, 1, 1} (assuming you want a 1 point border).

Do the same to the progressImage, and you'll end up with something that looks correct:

Correct progressView

tl;dr:

Your images need to be resizable.

Community
  • 1
  • 1
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • 1
    According to instruments, this is leaking. I'm using arc. Is anyone else having the same problem? It looks like it could be a UIProgressView bug. – rob Feb 09 '12 at 18:41
  • for some reason, this is only making the track image resizable and not the actual progress image but I'm set up each the same way. – Seany242 May 24 '12 at 02:46
  • @Seany242 yep, you'll need to make the `progressImage` a resizable image as well. – Dave DeLong May 24 '12 at 03:02
  • they are the same image, just different colors. I double checked and replaced the setTrackImage: and setProgressImage: variables (load and track, both uiimages set up the same way from the same image) and in both cases, the progress image didn't work but the track image did. ...? – Seany242 May 24 '12 at 03:11
  • @Seany242 sounds like great fodder for a new question – Dave DeLong May 24 '12 at 04:13
  • good idea. new question [here:](http://stackoverflow.com/questions/10738361/why-isnt-uiprogressview-progress-bar-resizable) – Seany242 May 24 '12 at 21:14
  • And if you want to use a track image with a specific size. Not resizable? How can I set the progress default blue line? – Camus Sep 21 '12 at 02:56
  • This is a terrific explanation of pixel scaling. 10/10 – Alexander Molloy Feb 11 '17 at 14:59