Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Workaround an annoying bug with iOS 7.1 where custom track and progress images for UIProgressView gets ignored
//
// JEProgressView.h
//
//
// Created by John Rommel Estropia on 2014/03/11.
// Copyright (c) 2014 John Rommel Estropia.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <UIKit/UIKit.h>
// iOS 7.1 bugfix
// http://stackoverflow.com/questions/22311516/uiprogressview-custom-track-and-progress-images-in-ios-7-1
@interface JEProgressView : UIProgressView
@end
//
// JEProgressView.m
//
//
// Created by John Rommel Estropia on 2014/03/11.
// Copyright (c) 2014 John Rommel Estropia.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "JEProgressView.h"
@interface JEProgressView ()
@property (nonatomic, weak) UIImageView *trackImageView;
@property (nonatomic, weak) UIImageView *progressImageView;
@end
@implementation JEProgressView
#pragma mark - NSObject
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self setupProgressView];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self setupProgressView];
}
return self;
}
#pragma mark - UIView
- (void)layoutSubviews
{
[super layoutSubviews];
UIImageView *trackImageView = self.trackImageView;
UIImageView *progressImageView = self.progressImageView;
if (!trackImageView || !progressImageView)
{
return;
}
CGRect bounds = self.bounds;
CGFloat boundsTop = CGRectGetMinY(bounds);
UIImage *trackImage = self.trackImage;
if (trackImage)
{
CGRect trackFrame = trackImageView.frame;
CGFloat trackHeight = trackImage.size.height;
trackImageView.frame = (CGRect){
.origin.x = CGRectGetMinX(trackFrame),
.origin.y = (boundsTop
+ ((CGRectGetHeight(bounds) - trackHeight) * 0.5f)),
.size.width = CGRectGetWidth(trackFrame),
.size.height = trackHeight
};
}
UIImage *progressImage = self.progressImage;
if (progressImage)
{
CGRect progressFrame = progressImageView.frame;
CGFloat progressHeight = progressImage.size.height;
progressImageView.frame = (CGRect){
.origin.x = CGRectGetMinX(progressFrame),
.origin.y = (boundsTop
+ ((CGRectGetHeight(bounds) - progressHeight) * 0.5f)),
.size.width = CGRectGetWidth(progressFrame),
.size.height = progressHeight
};
}
}
#pragma mark - UIProgressView
- (void)setProgressImage:(UIImage *)progressImage
{
[super setProgressImage:progressImage];
self.progressImageView.image = progressImage;
}
- (void)setTrackImage:(UIImage *)trackImage
{
[super setTrackImage:trackImage];
self.trackImageView.image = trackImage;
}
#pragma mark - private
- (void)setupProgressView
{
if ([self compareVersionString:[UIDevice currentDevice].systemVersion
withVersionString:@"7.1"] == NSOrderedAscending)
{
return;
}
NSArray *subviews = self.subviews;
if ([subviews count] != 2)
{
return;
}
for (UIView *subview in subviews)
{
if (![subview isKindOfClass:[UIImageView class]])
{
return;
}
}
self.trackImageView = subviews[0];
self.progressImageView = subviews[1];
self.trackImageView.image = self.trackImage;
self.progressImageView.image = self.progressImage;
}
- (NSComparisonResult)compareVersionString:(NSString *)versionString1
withVersionString:(NSString *)versionString2
{
NSArray *components1 = [versionString1 componentsSeparatedByString:@"."];
NSArray *components2 = [versionString2 componentsSeparatedByString:@"."];
NSUInteger components1Count = [components1 count];
NSUInteger components2Count = [components2 count];
NSUInteger partCount = MAX(components1Count, components2Count);
for (NSInteger part = 0; part < partCount; ++part)
{
if (part >= components1Count)
{
return NSOrderedAscending;
}
if (part >= components2Count)
{
return NSOrderedDescending;
}
NSString *part1String = components1[part];
NSString *part2String = components2[part];
NSInteger part1 = [part1String integerValue];
NSInteger part2 = [part2String integerValue];
if (part1 > part2)
{
return NSOrderedDescending;
}
if (part1 < part2)
{
return NSOrderedAscending;
}
}
return NSOrderedSame;
}
@end
@JohnEstropia

This comment has been minimized.

Show comment Hide comment
@JohnEstropia

JohnEstropia Mar 11, 2014

Workaround an annoying bug with iOS 7.1 where custom track and progress images for UIProgressView gets ignored.

http://openradar.io/16113307
http://stackoverflow.com/questions/22311516/uiprogressview-custom-track-and-progress-images-in-ios-7-1

Owner

JohnEstropia commented Mar 11, 2014

Workaround an annoying bug with iOS 7.1 where custom track and progress images for UIProgressView gets ignored.

http://openradar.io/16113307
http://stackoverflow.com/questions/22311516/uiprogressview-custom-track-and-progress-images-in-ios-7-1

@skamisetty-eprosoft

This comment has been minimized.

Show comment Hide comment
@skamisetty-eprosoft

skamisetty-eprosoft Mar 14, 2014

I used these files for 7.1 but couldn't solve issue for me...

I used these files for 7.1 but couldn't solve issue for me...

@skamisetty-eprosoft

This comment has been minimized.

Show comment Hide comment
@skamisetty-eprosoft

skamisetty-eprosoft Mar 14, 2014

Solved issue..But I need progress bar with round corner

Solved issue..But I need progress bar with round corner

@httpsgithub

This comment has been minimized.

Show comment Hide comment
@httpsgithub

httpsgithub Mar 20, 2014

Hi John,

self.tintColor = [UIColor clearColor];

this should be added in the contructors under [self setupProgressView];

Otherwise the default progress indicator can overlay the graphic one on refreshes of the UI.

Hi John,

self.tintColor = [UIColor clearColor];

this should be added in the contructors under [self setupProgressView];

Otherwise the default progress indicator can overlay the graphic one on refreshes of the UI.

@httpsgithub

This comment has been minimized.

Show comment Hide comment
@httpsgithub

httpsgithub Mar 20, 2014

Actually no, should be done in the setProgressImage...sorry.

Actually no, should be done in the setProgressImage...sorry.

@mrga

This comment has been minimized.

Show comment Hide comment
@mrga

mrga Mar 21, 2014

Good job... it's working like a charm.
What are Terms of Use for this JEProgressView?

mrga commented Mar 21, 2014

Good job... it's working like a charm.
What are Terms of Use for this JEProgressView?

@RyoAbe

This comment has been minimized.

Show comment Hide comment
@RyoAbe

RyoAbe Mar 25, 2014

What is license this JEProgressView for commercial use?

JEProgressViewを商用利用させていただきたいのですが、その場合のライセンスを教えて頂けますでしょうか?

RyoAbe commented Mar 25, 2014

What is license this JEProgressView for commercial use?

JEProgressViewを商用利用させていただきたいのですが、その場合のライセンスを教えて頂けますでしょうか?

@mcmatan

This comment has been minimized.

Show comment Hide comment
@mcmatan

mcmatan Mar 25, 2014

Thanks this is great

mcmatan commented Mar 25, 2014

Thanks this is great

@JohnEstropia

This comment has been minimized.

Show comment Hide comment
@JohnEstropia

JohnEstropia Mar 27, 2014

@httpsgithub
I haven't tested this, but does the default UIProgressView ignore tintColor when using custom images? If so I'll update the code. Our project clears out tintColor explicitly so I didn't notice.

@mrga
I'm intending to add this to my JEToolkit repository which uses MIT license. I added the license statement in the .h and .m files for now.

@RyoAbe
MITライセンスです。.hと.mに入れておきました。

Owner

JohnEstropia commented Mar 27, 2014

@httpsgithub
I haven't tested this, but does the default UIProgressView ignore tintColor when using custom images? If so I'll update the code. Our project clears out tintColor explicitly so I didn't notice.

@mrga
I'm intending to add this to my JEToolkit repository which uses MIT license. I added the license statement in the .h and .m files for now.

@RyoAbe
MITライセンスです。.hと.mに入れておきました。

@JackTheNoob

This comment has been minimized.

Show comment Hide comment
@JackTheNoob

JackTheNoob Apr 15, 2014

@JohnEstropia
It works,but not works perfectly.
Here is a problem I met:
Present a JEProgressView on a controller's view.Then show a alertview (or a new window). The JEProgressView's apperance changes.progressTintColor turns to blue. (Sorry about my poor English,hope you can catch my meaning)

@JohnEstropia
It works,but not works perfectly.
Here is a problem I met:
Present a JEProgressView on a controller's view.Then show a alertview (or a new window). The JEProgressView's apperance changes.progressTintColor turns to blue. (Sorry about my poor English,hope you can catch my meaning)

@mtancock

This comment has been minimized.

Show comment Hide comment
@mtancock

mtancock Apr 16, 2014

It seems (in my trial) that it doesn't work when setting a progressview up in a storyboard - the setProgressImage/TrackImage methods don't get called. If I set it up in code, those methods get called. (And I have changed the class of the progressView in the storyboard to the JEProgressView)

Cheers for your work on this!!

It seems (in my trial) that it doesn't work when setting a progressview up in a storyboard - the setProgressImage/TrackImage methods don't get called. If I set it up in code, those methods get called. (And I have changed the class of the progressView in the storyboard to the JEProgressView)

Cheers for your work on this!!

@JohnEstropia

This comment has been minimized.

Show comment Hide comment
@JohnEstropia

JohnEstropia Apr 18, 2014

@JackTheNoob
as @httpsgithub mentioned above, you seem to also need to set
self.tintColor = [UIColor clearColor];
so your image doesn't turn blue. I'd automatically set the tintColor to clearColor if the images are not null, but I don't want to change the behavior of the original UIProgressView.

@mtancock
Probably because images in storyboards are set straight within -[initWithCoder:]. You did raise a common use case so I'll include a fix for this.

Owner

JohnEstropia commented Apr 18, 2014

@JackTheNoob
as @httpsgithub mentioned above, you seem to also need to set
self.tintColor = [UIColor clearColor];
so your image doesn't turn blue. I'd automatically set the tintColor to clearColor if the images are not null, but I don't want to change the behavior of the original UIProgressView.

@mtancock
Probably because images in storyboards are set straight within -[initWithCoder:]. You did raise a common use case so I'll include a fix for this.

@maxgribov

This comment has been minimized.

Show comment Hide comment
@maxgribov

maxgribov Apr 20, 2014

Problem: AlertView drops custom image from JEProgressView's ProgressImage and change it on default values (plane color). By the way TrackImage is ok.

Problem: AlertView drops custom image from JEProgressView's ProgressImage and change it on default values (plane color). By the way TrackImage is ok.

@oklimberg

This comment has been minimized.

Show comment Hide comment
@oklimberg

oklimberg May 7, 2014

Hi,

thanks for this fix. It totally fits my needs in a project.
Could you explain, why you calculate the origin on the y-axis of the image views the way you are doing it? With your original Code, the two imageViews will have an origin of -7.25 using images with a height of 17px, cause the heigth of the UIProgressView itself is 2,5px, even though I set a frame with a height of 17px.

When I change the line

.origin.y = (boundsTop + ((CGRectGetHeight(bounds) - trackHeight) * 0.5f)),

to

.origin.y = CGRectGetMinY(trackFrame),

the progress image view is positioned as expected. (I do not use an image for the track)

Regards
Oliver

Hi,

thanks for this fix. It totally fits my needs in a project.
Could you explain, why you calculate the origin on the y-axis of the image views the way you are doing it? With your original Code, the two imageViews will have an origin of -7.25 using images with a height of 17px, cause the heigth of the UIProgressView itself is 2,5px, even though I set a frame with a height of 17px.

When I change the line

.origin.y = (boundsTop + ((CGRectGetHeight(bounds) - trackHeight) * 0.5f)),

to

.origin.y = CGRectGetMinY(trackFrame),

the progress image view is positioned as expected. (I do not use an image for the track)

Regards
Oliver

@JohnEstropia

This comment has been minimized.

Show comment Hide comment
@JohnEstropia

JohnEstropia May 11, 2014

@oklimberg: My computation makes it so that the imageViews are vertically centered within the parent UIProgressView.

Owner

JohnEstropia commented May 11, 2014

@oklimberg: My computation makes it so that the imageViews are vertically centered within the parent UIProgressView.

@timstudt

This comment has been minimized.

Show comment Hide comment
@timstudt

timstudt Oct 27, 2014

works great.

Note: height of progressView is still set to 2., so remember to set progressBar.clipsToBounds=NO

works great.

Note: height of progressView is still set to 2., so remember to set progressBar.clipsToBounds=NO

@berikv

This comment has been minimized.

Show comment Hide comment
@berikv

berikv Dec 8, 2014

Why not just

- (void)drawRect:(CGRect)rect {
    double progress = MIN(1, MAX(0, self.progress));

    [self.progressBackgroundImage drawInRect:rect];

    CGRect progressFrame = rect;
    progressFrame.size.width = round(rect.size.width * progress);

    [self.progressImage drawInRect:progressFrame];
}

and not subclass UIProgressView?

berikv commented Dec 8, 2014

Why not just

- (void)drawRect:(CGRect)rect {
    double progress = MIN(1, MAX(0, self.progress));

    [self.progressBackgroundImage drawInRect:rect];

    CGRect progressFrame = rect;
    progressFrame.size.width = round(rect.size.width * progress);

    [self.progressImage drawInRect:progressFrame];
}

and not subclass UIProgressView?

@karnakar

This comment has been minimized.

Show comment Hide comment
@karnakar

karnakar Feb 6, 2015

Hi,
I have been searching for the same solution for a long time, thanks. Can i make progress view round cornered at the corners.

karnakar commented Feb 6, 2015

Hi,
I have been searching for the same solution for a long time, thanks. Can i make progress view round cornered at the corners.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment