#ios #iphone #ipad #uiview #initwithcoder
#iOS #iPhone #iPad #пользовательский просмотр #initwithcoder
Вопрос:
Есть пара вопросов, задающих этот вопрос на SO, но ни один из них не задал этого должным образом.
Я использую пользовательский индикатор выполнения, который является UIView
классом на основе этой реализации.
@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];
}
Я создал UIView
в Interface Builder файл размером 200×20 точек и присвоил этому представлению этот пользовательский класс, который MCProgressBarView
я использую. Когда приложение запускается, initWithCoder
запускается и создает представление прогресса размером 1000×1000 точек, не обращая внимания на размер, который имеет представление в IB.
Как мне заставить initWithCoder запускаться с правильным размером, назначенным в IB?
ПРИМЕЧАНИЕ: Я не хочу жестко привязывать это к 200×20 и не хочу устанавливать это с помощью кода во время выполнения. Есть ли способ заставить это работать?
Ответ №1:
TL; DR: Переместите свою логику фрейма / границ в viewDidLayoutSubviews
.
initWithCoder:
небезопасно для выполнения логики фрейма. Для этого вам следует использовать viewDidLayoutSubviews
. Apple использует границы 1000×1000, начиная с iOS 10. Неясно, ошибка ли это или преднамеренный, но, похоже, у этого есть чистый положительный результат — люди приходят сюда и спрашивают об этом. ;-)
На самом деле, initWithCoder:
такая логика никогда не была безопасной. Раньше у вас был бы вид, границы которого совпадали бы с границами экрана iPhone 5, потому что это то, что вы использовали в IB, но затем вид увеличился бы до размера iPhone 6 Plus или iPad, и это вызвало бы визуальные проблемы.
Теперь Apple просто устанавливает границы в 1000×1000, что неверно для всех случаев. Границы исправляются после выполнения прохода макета в представлении.
Комментарии:
1. В классе на основе UIView нет viewDidLayoutSubviews. Если я использую ViewController для правильной настройки размера представления, то все это плохо задумано Apple как множество вещей на ios.
2. Использование @SpaceDog
layoutSubviews
.3. ОК. Я реализовал
layoutSubviews
в классе. Когда выполняется этот метод, вид имеет правильный размер без необходимости что-либо делать, но когда он отображается в приложении, он равен 1000×1000.4. Пожалуйста, опубликуйте скриншоты. Что-то звучит странно.