UIViewController viewDidLoad некорректная ширина/высота

Всем известно, что вы не можете доверять размеру фрейма в методе init/viewDidLoad UIViewController; это:

- (void)viewDidLoad: {
     NSLog(@"%d", self.view.frame.size.width);
}

будет печатать неправильные размеры во многих случаях (в частности, он сильно разбит в ландшафтном режиме)

Это приведет к возврату всегда скорректированных результатов, поэтому неплохо разместить макеты субвью:

- (void)viewWillAppear: {
     NSLog(@"%d", self.view.frame.size.width);
}

Проблема заключается в том, что viewWillAppears вызывается каждый раз, когда появляется представление, поэтому он не подходит для размещения или добавления subviews. Таким образом, вы в конечном итоге объявляете каждый вид в интерфейсе, и в итоге вы получаете огромные файлы заголовков, которые мне совсем не нравятся, поскольку большинству элементов больше не нужны манипуляции после начальной настройки.

Итак, первый вопрос: Есть ли лучший способ для обработки позиционирования подпрограмм?

Вопрос два очень связан, скажем, у меня есть подкласс UIView, включая различные другие подпункты. Я объявляю его внутри своего интерфейса, и я выделяю/инициализирую его в методе init/viewDidLoad.

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    ...
    menu = [[SNKSlidingMenu alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
    ...
}

Как мы уже знаем, теперь нам нужно переместить его в viewWillAppear, чтобы получить более точное чтение

- (void)viewWillAppear:(BOOL)animated{
    ....
    menu.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
    ....
 }

Проблема заключается в том, что, конечно, все подсмотры также необходимо переместить. Это выполняется с помощью функции layoutSubviews, которая вызывается автоматически, но у нас есть та же проблема: Все подзапросы должны быть объявлены внутри интерфейса класса SNKSlidingMenu. Есть ли способ обойти это?

Спасибо.

Ответ 1

Если вы настроите iOS 5.0 или лучше, вы можете использовать viewWillLayoutSubviews и viewDidLayoutSubviews для внесения изменений.

Что касается вашего второго вопроса, если вам нужен доступ к переменной экземпляра в другом методе, чем init, вам нужно сохранить его, я не вижу проблемы с ним.

Однако вы можете использовать автоматические макеты и настраивать правила между подзонами, чтобы они автоматически выкладывались для вас без необходимости сохранять ссылку.

Ответ 2

viewDidLoad вызывается только при создании вашего представления, но многие вещи могут повлиять на размер frame, и он не будет вызван снова, когда изменяется frame.

Вместо

  • создать подпрограммы в viewDidLoad
  • установить их размеры в viewWillLayoutSubviews.

См. дополнительную информацию для обработки вращения: fooobar.com/questions/164519/...

Ответ 3

viewWillLayoutSubviews и viewDidLayoutSubviews могут решить эту проблему.
Но два methed будут выполняться больше раз. это мой код, чтобы получить правильный self.view.frame.

- (void)viewDidLoad {
  [super viewDidLoad];  
  ...  
  dispatch_async(dispatch_get_main_queue(), ^{  
   // init you view and set it`s frame. this can get correct frame.   
   ...  
  }  
  ...  
}

Ответ 4

Это спасло мою жизнь не раз:

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.setNeedsLayout()
    self.view.layoutIfNeeded()
}

В основном это заставляет viewcontroller правильно расположить его представление, и оттуда вы можете получить правильные кадры для всех ваших подпредставлений. Это особенно помогает при анимации переходов, а ваши контроллеры представления используют autolayout и построитель интерфейса.

Из того, что я заметил, похоже, что начальные кадры установлены в соответствии с тем, какой класс размера по умолчанию установлен в вашем конструкторе интерфейсов. Я обычно редактирую, используя класс размера iPhone XS, поэтому в viewDidLoad кажется, что ширина просмотра всегда равна 375 независимо от того, используете ли вы iPhone XR или нет. Это исправляет себя перед viewWillAppear, хотя.

Приведенный выше код исправит эту проблему и позволит вам получить правильные кадры для вашего представления/подпредставления до того, как ViewController будет отображен на экране.