Просмотр 1000x1000 на 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 на построителе интерфейса, чтобы быть 200x20 точек и назначил это представление для этого пользовательского класса MCProgressBarView Я использую. Когда приложение запускается, initWithCoder запускает и создает представление прогресса с размером 1000x1000 точек, независимо от размера представления IB.

Как заставить initWithCoder работать с правильным размером, назначенным на IB?

ПРИМЕЧАНИЕ: я не хочу жестко привязывать это к 200x20, и я не хочу устанавливать это кодом во время выполнения. Есть ли способ сделать эту работу?

1 ответ

Решение

TL;DR: переместите логику фрейма / границ в viewDidLayoutSubviews,

initWithCoder: не безопасно для выполнения логики кадра. Вы должны использовать viewDidLayoutSubviews для этого. Apple использует 1000x1000 границ, начиная с iOS 10. Неясно, является ли ошибка или преднамеренной, но это, похоже, дает чистый положительный результат - люди приходят сюда и спрашивают об этом. ;-)

По факту, initWithCoder: никогда не был безопасен для такой логики. Раньше у вас было представление, границы которого будут такими же, как на экране iPhone 5, потому что это то, что вы использовали в IB, но тогда представление увеличилось бы до размера iPhone 6 Plus или размера iPad, и это могло бы вызвать визуальные проблемы.

Теперь Apple просто устанавливает границы на 1000x1000, что неверно для всех случаев. Границы исправляются после выполнения макета в представлении.

Другие вопросы по тегам