Когда вызывается 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)
    }
}