There are a couple of questions asking this on SO but none have asked that properly.
I am using a custom progress bar that is a UIView based class with this implementation.
@implementation MCProgressBarView {
UIImageView * _backgroundImageView;
UIImageView * _foregroundImageView;
CGFloat minimumForegroundWidth;
CGFloat availableWidth;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
// [self bounds] is 1000x1000 here... what?
if (self) [self initialize];
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) [self initialize];
return self;
}
- (void) initialize {
UIImage * backgroundImage = [[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"progress-bg" ofType:@"png"]]
resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f)];
UIImage * foregroundImage = [[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"progress-bg" ofType:@"png"]]
resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f)];
_backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
_backgroundImageView.image = backgroundImage;
[self addSubview:_backgroundImageView];
_foregroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
_foregroundImageView.image = foregroundImage;
[self addSubview:_foregroundImageView];
UIEdgeInsets insets = foregroundImage.capInsets;
minimumForegroundWidth = insets.left + insets.right;
availableWidth = self.bounds.size.width - minimumForegroundWidth;
[self adjustProgress:0.0f];
}
I have created a UIView on interface builder to be 200x20 points and assigned that view to be of this custom class MCProgressBarView I am using. When the app runs, initWithCoder runs and creates a progress view with a size of 1000x1000 points, disregarding the size that the view has on IB.
How do I force initWithCoder to run with the proper size assigned on IB?
NOTE: I don't want to hard wire that to 200x20 and I don't want to set this by code at run time. Is there a way to make this work?
TL;DR: Move your frame/bounds logic to
viewDidLayoutSubviews.initWithCoder:is not safe for performing frame logic. You should useviewDidLayoutSubviewsfor that. Apple uses 1000x1000 bounds starting with iOS 10. It is unclear if bug or intentional, but it seems to have a net positive outcome - people come here and ask about it.;-)In fact,
initWithCoder:has never been safe for such logic. In the past, you'd have a view whose bounds would be those of iPhone 5's screen because that was what you used in IB, but then the view would grow to iPhone 6 Plus size or iPad size, and it would cause visual issues.Now, Apple just sets the bounds to 1000x1000, which is incorrect for all cases. The bounds are corrected once a layout pass is performed on the view.