Как эффективно управлять изменениями размера экрана и перерисовкой с помощью раскадровок, initWithCoder, viewDidLoad и viewDidLayoutSubviews?

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

Я поддерживаю макеты iPhone и iPad.

Когда представление создается с initWithCoder:, он изначально создается с размером кадра устройства, на которое я последний раз смотрел в Интерфейсном Разработчике.

Если я проектирую макет iPhone X в конструкторе интерфейсов, а затем собираю и запускаю на iPad, представление изначально создается с размерами экрана iPhone X. затем viewDidLayoutSubviews: и обновляет размеры экрана до правильного размера iPad.

  1. Подвиды используют drawRect внутри UIViews, чтобы нарисовать графику просмотра. Я делаю это, чтобы я мог изменить графические цвета с помощью кода. Я изменяю переменную цвета и затем вызываю setNeedsDispay на вид, чтобы перерисовать вид с новыми цветами, используя CGGraphicsContext команды.

  2. Это также позволяет мне рисовать любое графическое изображение в любом размере. А с большим количеством графики это означает, что мне не нужно включать все разные изображения в размерах 1x, 2x и 3x в свой комплект. Это все нарисовано динамически.

  3. Некоторые из этих изображений размещаются при загрузке представления, а не в Интерфейсном Разработчике. Поэтому я проверяю размер экрана и рисую размер и положение кнопки соответственно.

Что происходит, viewDidLoad вызывается и рисует графику на основе начального размера экрана.

затем viewDidLayoutSubviews вызывается, и я должен обновить чертеж подвидов, которые я поместил, вручную, переставляя их на основе новых размеров экрана, а затем вызывая drawRect на них. Я чувствую, что это просто ненужная дополнительная работа для устройства.

В дополнение к этому, viewDidLayoutSubviews вызывается по другим причинам, а затем просто изменяет размер представления при начальной загрузке viewController. Поэтому каждый раз, когда он вызывается, он перерисовывает подпредставления, даже если они им не нужны.

И, если устройство, на котором я работаю, совпадает с устройством, которое я использовал в Интерфейсном Разработчике, оно не вызывает viewDidLayoutSubviews, Я не могу просто позволить макету представления подпредставлений там, потому что нет никакой гарантии, что он будет вызван.

Мое решение до сих пор заключается в создании переменной для отслеживания ширины экрана. Я установил переменную в viewDidLoad, Если это создает представление в размере iPhone X, мой screenWidthTracker = 1125, когда viewDidLayoutSubviews Я сравниваю текущий размер экрана с screenWidthTracker.

if (self.view.frame != screenWidthTracker) {
     [[NSNotificationCenter defaultCenter] postNotificationName:@"updateView" object:self];
};

если представление изменило размер, оно отправляет сообщение перерисовать представления. Любые представления, которые я поместил вручную как подпредставления, регистрируются для прослушивания @"updateView".

Есть ли лучший способ справиться с этим? Существует ли метод, который вызывается ТОЛЬКО при изменении размеров экрана, а не при обновлении позиции других подпредставлений? Должен ли я использовать viewDidAppear? Мне кажется, что уже слишком поздно в цепочке, и я не хочу, чтобы пользователь видел обновления размера кнопки.

1 ответ

В целом, из приведенного вами описания я бы сказал, что в большинстве случаев вы должны выполнять как можно больше работы с размерами, используя автопоставку (которую вы можете полностью настроить в раскадровке), а затем реализовывать только drawRect а также viewDidLayoutSubviews - и последнее, только если вам нужно.

Очень распространенная стратегия заключается в использовании логического флага для установки начальных условий при первом вызове viewDidLayoutSubviewsи не использовать его после этого. Изменения размера экрана после запуска (не при запуске), такие как поворот, обнаруживаются путем реализации willTransition(to:with:) - и даже тогда вы должны проверить, что старый размер и новый размер не совпадают (поворот на 180 градусов) и ничего не делать, если они есть.

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