Как эффективно управлять изменениями размера экрана и перерисовкой с помощью раскадровок, initWithCoder, viewDidLoad и viewDidLayoutSubviews?
Я использую макеты раскадровки, чтобы настроить макет представления.
Я поддерживаю макеты iPhone и iPad.
Когда представление создается с initWithCoder:
, он изначально создается с размером кадра устройства, на которое я последний раз смотрел в Интерфейсном Разработчике.
Если я проектирую макет iPhone X в конструкторе интерфейсов, а затем собираю и запускаю на iPad, представление изначально создается с размерами экрана iPhone X. затем viewDidLayoutSubviews:
и обновляет размеры экрана до правильного размера iPad.
Подвиды используют
drawRect
внутри UIViews, чтобы нарисовать графику просмотра. Я делаю это, чтобы я мог изменить графические цвета с помощью кода. Я изменяю переменную цвета и затем вызываюsetNeedsDispay
на вид, чтобы перерисовать вид с новыми цветами, используяCGGraphicsContext
команды.Это также позволяет мне рисовать любое графическое изображение в любом размере. А с большим количеством графики это означает, что мне не нужно включать все разные изображения в размерах 1x, 2x и 3x в свой комплект. Это все нарисовано динамически.
Некоторые из этих изображений размещаются при загрузке представления, а не в Интерфейсном Разработчике. Поэтому я проверяю размер экрана и рисую размер и положение кнопки соответственно.
Что происходит, 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 градусов) и ничего не делать, если они есть.