Когда вызывается layoutSubviews?
У меня есть пользовательский вид, который не получает layoutSubview
сообщения во время анимации.
У меня есть вид, который заполняет экран. У него есть настраиваемое подпредставление в нижней части экрана, которое правильно изменяет размеры в Интерфейсном Разработчике, если я изменяю высоту панели навигации. layoutSubviews
вызывается при создании представления, но никогда больше Мои подпредставления правильно выложены. Если я отключаю строку состояния в вызове, подпредставление layoutSubviews
не вызывается вообще, хотя основной вид оживляет его изменение размера.
При каких обстоятельствах layoutSubviews
на самом деле называется?
я имею autoresizesSubviews
установлен в NO
для моего собственного просмотра. А в Интерфейсном Разработчике у меня есть верхняя и нижняя распорки и вертикальная стрелка.
10 ответов
Я отследил решение до настойчивости Интерфейсного Разработчика, что пружины не могут быть изменены в представлении, у которого включены моделируемые элементы экрана (строка состояния и т. Д.). Поскольку пружины были отключены для основного вида, этот вид не мог изменить размер и, следовательно, был прокручен полностью во время появления панели вызова.
Выключение смоделированных объектов, изменение размера вида и правильная установка пружин привели к возникновению анимации и вызову моего метода.
Дополнительная проблема при отладке заключается в том, что симулятор закрывает приложение, когда статус вызова вызывается через меню. Выйти из приложения = нет отладчика.
У меня был похожий вопрос, но я не был удовлетворен ответом (или любым другим, который я мог найти в сети), поэтому я попробовал его на практике, и вот что я получил:
init
не вызываетlayoutSubviews
быть призваннымaddSubview:
причиныlayoutSubviews
вызываться для добавляемого представления, представления, к которому оно добавляется (представление цели), и всех подпредставлений цели- Посмотреть
setFrame
разумно называетlayoutSubviews
в представлении с установленным кадром, только если параметр размера кадра отличается - прокрутка UIScrollView вызывает
layoutSubviews
вызываться в scrollView и его суперпредставлении - вращение устройства только звонки
layoutSubview
в родительском представлении (отвечающее первичное представление viewControllers) - Изменение размера представления вызовет
layoutSubviews
на своем супервизии
Мои результаты - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
Основываясь на предыдущем ответе @BadPirate, я немного поэкспериментировал и предложил некоторые уточнения / исправления. я нашел это layoutSubviews:
будет вызываться в представлении, если и только если:
- Изменились собственные границы (не рамки).
- Границы одного из его прямых подпредставлений изменились.
- Подвид добавляется в представление или удаляется из представления.
Некоторые важные детали:
- Границы считаются измененными, только если новое значение отличается, включая другое происхождение. Обратите внимание, что именно поэтому
layoutSubviews:
вызывается всякий раз, когда прокручивается UIScrollView, так как он выполняет прокрутку, изменяя источник своих границ. - Изменение фрейма изменит только границы, если размер изменился, так как это единственное, что распространяется на свойство bounds.
- Изменение границ представления, которое еще не находится в иерархии представления, приведет к вызову
layoutSubviews:
когда представление в конечном итоге добавляется в иерархию представлений. - И просто для полноты: эти триггеры напрямую не вызывают layoutSubviews, а скорее вызывают
setNeedsLayout
, который устанавливает / поднимает флаг. На каждой итерации цикла выполнения для всех представлений в иерархии представлений этот флаг проверяется. Для каждого вида, где флаг поднят,layoutSubviews:
вызывается и флаг сбрасывается. Представления выше по иерархии будут проверены / вызваны первыми.
Изменения макета могут происходить всякий раз, когда в представлении происходит любое из следующих событий:
а. Размер прямоугольника границ представления изменяется.
б. Происходит изменение ориентации интерфейса, которое обычно вызывает изменение прямоугольника границ корневого представления.
с. Набор подслоев Core Animation, связанных со слоем представления, изменяется и требует компоновки.
д. Ваше приложение вызывает макет, вызываяsetNeedsLayout
или жеlayoutIfNeeded
метод зрения.
е. Ваше приложение вызывает макет, вызываяsetNeedsLayout
метод объекта базового уровня представления.
Некоторые из пунктов в ответе BadPirate верны лишь частично:
За
addSubView
точкаaddSubview
заставляет layoutSubviews вызываться для добавляемого представления, представления, к которому оно добавляется (представление цели), и всех подпредставлений цели.Это зависит от маски авторазмера вида (целевого вида). Если он имеет маску автоматического изменения размера, layoutSubview будет вызываться на каждом
addSubview
, Если у него нет маски авторазмера, то layoutSubview будет вызываться только при изменении размера кадра представления (целевого представления).Пример: если вы создали UIView программно (по умолчанию он не имеет маски авторазмера), LayoutSubview будет вызываться только тогда, когда кадр UIView изменяется не на каждом
addSubview
,Именно благодаря этой технике производительность приложения также увеличивается.
Для точки вращения устройства
Вращение устройства вызывает layoutSubview только для родительского представления (основного представления отвечающего viewController)
Это может быть правдой, только если ваш VC находится в иерархии VC (root в
window.rootViewController
), ну это самый распространенный случай. В iOS 5, если вы создаете VC, но он не добавляется ни в один другой VC, тогда этот VC не будет замечен при повороте устройства. Поэтому его представление не будет замечено вызовом layoutSubviews.
Призвание [self.view setNeedsLayout];
в viewController делает это, чтобы вызвать viewDidLayoutSubviews
Вы смотрели на layoutIfNeeded?
Фрагмент документации ниже. Работает ли анимация, если вы вызываете этот метод явно во время анимации?
layoutIfNeeded Выкладывает подпредставления, если это необходимо.
- (void)layoutIfNeeded
Обсуждение Используйте этот метод для принудительного размещения макетов подпредставлений перед рисованием.
Доступность Доступно в iPhone OS 2.0 и более поздних версиях.
При переносе приложения OpenGL из SDK 3 в 4 layoutSubviews больше не вызывался. После долгих проб и ошибок я наконец открыл MainWindow.xib, выбрал объект Window, в инспекторе выбрал вкладку Window Attributes (крайний левый) и установил флажок "Видимо при запуске". Кажется, что в SDK 3 он все еще вызывал вызов layoutSubViews, но не в 4.
6 часов разочарования подошли к концу.
Другая часть головоломки заключается в том, что окно должно быть сделано ключом:
[window makeKeyAndVisible];
иначе подпредставления не изменяются автоматически.
Довольно неясный, но потенциально важный случай, когда layoutSubviews
никогда не вызывается
import UIKit
class View: UIView {
override class var layerClass: AnyClass { return Layer.self }
class Layer: CALayer {
override func layoutSublayers() {
// if we don't call super.layoutSublayers()...
print(type(of: self), #function)
}
}
override func layoutSubviews() {
// ... this method never gets called by the OS!
print(type(of: self), #function)
}
}
let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))