Когда вызывается layoutSubviews?
У меня есть пользовательский вид, который не получает сообщения layoutSubview
во время анимации.
У меня есть представление, которое заполняет экран. В нижней части экрана есть настраиваемый подзаголовок, который правильно изменяет размеры в Interface Builder, если я изменяю высоту панели навигации. layoutSubviews
вызывается при создании представления, но никогда больше. Мои подпрограммы правильно выложены. Если я отключу строку состояния вызова в выключенном состоянии, subview layoutSubviews
вообще не вызывается, даже если основной вид делает анимирование его размера.
В каких обстоятельствах действительно называется layoutSubviews
?
У меня autoresizesSubviews
установлен на NO
для моего пользовательского представления. И в Interface Builder у меня есть верхняя и нижняя стойки и вертикальная стрелка.
Ответы
Ответ 1
Я отслеживал решение вплоть до настойчивости Interface Builder, что пружины не могут быть изменены в представлении с включенными имитируемыми элементами экрана (строка состояния и т.д.). Поскольку пружины были отключены для основного вида, этот вид не мог изменить размер и, следовательно, был прокручен в полном объеме, когда появилась панель вызова.
Отключение симулированных функций, изменение размера и правильность настройки пружин, вызвавших анимацию, и мой метод для вызова.
Дополнительная проблема при отладке заключается в том, что симулятор покидает приложение, когда статус вызова в режиме вызова переключается через меню. Выйти из приложения = нет отладчика.
Ответ 2
У меня был аналогичный вопрос, но я не был удовлетворен ответом (или любым, что мог найти в сети), поэтому я попробовал его на практике, и вот что я получил:
-
init
не вызывает layoutSubviews
для
(duh)
-
addSubview:
причины
layoutSubviews
для вызова на
добавление вида, представление его
добавлен в (целевой вид), и все
subviews цели
- view
setFrame
интеллектуально называет layoutSubviews
on
вид, имеющий только набор кадров
если параметр размера кадра равен
отличается
- прокрутка UIScrollView
вызывает вызов
layoutSubviews
scrollView и его супервизор
- вращение устройства вызывает только вызовы
layoutSubview
на родительском представлении (
отвечающий viewControllers primary
вид)
- Изменение размера представления вызовет
layoutSubviews
в своем супервизоре
Мои результаты - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
Ответ 3
Основываясь на предыдущем ответе @BadPirate, я немного экспериментировал и придумал некоторые пояснения/исправления. Я обнаружил, что layoutSubviews:
будет вызываться в представлении тогда и только тогда, когда:
- Изменены собственные границы (не фрейм).
- Изменены границы одного из его прямых подходов.
- Под просмотр добавляется в представление или удаляется из представления.
Некоторые релевантные детали:
- Оценки считаются измененными только в том случае, если новое значение отличается от другого, включая другое происхождение. Обратите внимание, что именно поэтому
layoutSubviews:
вызывается всякий раз, когда прокручивается UIScrollView, поскольку он выполняет прокрутку, изменяя начало своих границ.
- Изменение фрейма изменит границы только в том случае, если размер был изменен, и это единственное, что в любом случае распространяется на свойство bounds.
- Изменение границ представления, которое еще не находится в иерархии представлений, приведет к вызову
layoutSubviews:
, когда представление в конечном итоге будет добавлено в иерархию представлений.
- И только для полноты: эти триггеры напрямую не ссылаются на layoutSubviews, а скорее на вызов
setNeedsLayout
, который устанавливает/повышает флаг. Каждая итерация цикла запуска, для всех представлений в иерархии представлений, проверяется этот флаг. Для каждого вида, где флаг найден поднятым, на него вызывается layoutSubviews:
, а флаг - reset. Сначала будут проверены/вызваны представления выше иерархии.
Ответ 4
Некоторые из пунктов в ответе BadPirate являются лишь частично истинными:
-
Для addSubView
точки
addSubView
вызывает отображение layoutSubviews в добавляемом представлении, представление его добавляется в (целевой вид) и все подчиненные объекты цели.
Это зависит от маски ауразризации вида (целевого представления). Если он активирует маску ON, layoutSubview будет вызываться на каждом addSubView
. Если у него нет маски автосохранения, то layoutSubview будет вызываться только тогда, когда изменяется размер кадра представления (целевой вид).
Пример: если вы создали программный код UIView (по умолчанию он не имеет маски авторазрезания), LayoutSubview будет вызываться только тогда, когда кадр UIView изменяется не на каждом addSubView
.
Именно благодаря этому методу производительность приложения также увеличивается.
-
Для точки вращения устройства
Поворот устройства вызывает только layoutSubview на родительском представлении (основной вид отвечающего viewController)
Это может быть справедливо только тогда, когда ваш VC находится в иерархии VC (root at window.rootViewController
), и это наиболее распространенный случай. В iOS 5, если вы создаете VC, но он не добавлен в какой-либо другой VC, тогда этот VC не будет замечен при повороте устройства. Поэтому его взгляд не будет замечен вызовом layoutSubviews.
Ответ 5
призвание
[self.view setNeedsLayout];
in viewController позволяет вызвать viewDidLayoutSubviews
Ответ 6
https://developer.apple.com/library/prerelease/tvos/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1
Изменения макета могут возникать всякий раз, когда происходит какое-либо из следующих событий в представлении:
а. Изменяется размер прямоугольника с ограничениями просмотров.
б. Происходит изменение ориентации интерфейса, которое обычно вызывает изменение в прямоугольнике границ корневых представлений.
с. Набор подслоев Core Animation, связанных с уровнем просмотров, изменяет и требует макета.
д. Ваше приложение заставляет макет выполняться, вызывая метод setNeedsLayout
или layoutIfNeeded
для представления.
е. Ваше приложение заставляет компоновку вызывать метод setNeedsLayout
для объектов, лежащих в основе слоя.
![]()
Ответ 7
Вы посмотрели на layoutIfNeeded?
Ниже приведен фрагмент документации. Работает ли анимация, если вы вызываете этот метод явно во время анимации?
layoutIfNeeded
При необходимости откладывает подсмотры.
- (void)layoutIfNeeded
Обсуждение
Используйте этот метод для принудительного расположения надзоров перед рисованием.
Наличие
Доступно в iPhone OS 2.0 и более поздних версиях.
Ответ 8
При переносе приложения OpenGL из SDK 3 в 4, layoutSubviews больше не вызывался. После большого количества проб и ошибок я, наконец, открыл MainWindow.xib, выбрал объект Window, в инспекторе выбрал вкладку "Атрибуты окна" (слева) и отметит "Visible at launch". Похоже, что в SDK 3 он все еще использовался для вызова layoutSubViews, но не в 4.
6 часов разочарования заканчиваются.
Ответ 9
Еще одна часть головоломки заключается в том, что окно должно быть сделанным ключом:
[window makeKeyAndVisible];
of other, подпункты не изменяются автоматически.
Ответ 10
Другой довольно неясный, но очень важный случай, когда layoutSubviews
никогда не вызывается:
class View: UIView {
override class var layerClass: AnyClass { return Layer.self }
class Layer: CALayer {
override func layoutSublayers() {
// if we don't call super.layoutSublayers()
}
}
override func layoutSubviews() { // this never gets called by the OS!
print(#function)
}
}