Ответ
viewDidLayoutSubviews() — это наиболее подходящий метод для получения окончательных размеров и позиций view.
Почему? Этот метод вызывается после того, как система завершила расчет layout для контроллера и всех его subviews. Значения frame и bounds здесь гарантированно актуальны.
Пример:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Теперь frame корневой view корректен
print("Main view frame: (view.frame)")
// Можно безопасно позиционировать subviews
customSubview.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 100)
}
Важные нюансы:
viewDidLoad()— не подходит, так как view загружена в память, но её geometry (размеры и положение) ещё не рассчитана относительно родительского контекста (окна, safe area).viewWillAppear(_:)— тоже может давать некорректные значения, так как final layout ещё не выполнен.viewDidAppear(_:)— даст правильные значения, но вызывается позже, после появления view на экране, что может быть слишком поздно для начальной настройки UI.- Метод
viewDidLayoutSubviews()может вызываться несколько раз (поворот, изменение constraints, вызовsetNeedsLayout()). Для однократной настройки используйте флаг:private var isFirstLayout = true override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if isFirstLayout { isFirstLayout = false // Настройка, выполняемая один раз } }
Ответ 18+ 🔞
А, ну вот, опять про эти ваши вьюхи и фреймы, блядь! Слушай, тут один чувак вечно в viewDidLoad лезет, как будто там уже всё нарисовано, а потом охуевает, что у него ноль на ноль. Так вот, запомни раз и навсегда, ёпта!
viewDidLayoutSubviews() — это, сука, святое место, где можно наконец-то получить настоящие, живые размеры. Почему? Да потому что система тут уже всю эту хуйню с авто-лейаутом, констрейнтами и safe area переварила и выдала итоговый результат. Фреймы здесь — не пустые обещания, а реальные цифры.
Смотри, как это работает:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Вот теперь frame корневой вьюхи — это правда, а не пиздёж
print("Main view frame: (view.frame)")
// И можно уже без бздёта расставлять свои сабвьюхи
customSubview.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 100)
}
А теперь про основные грабли, об которые все ебут лбы:
viewDidLoad()— полная хуйня для размеров! Вьюха в памяти есть, да, но её геометрия — это как чертёж на салфетке. Она ещё не знает, в каком окне её повесят и какие отступы safe area сожрут.viewWillAppear(_:)— тоже, блядь, не айс. Финальный лейаут ещё не просчитан, можно получить левые цифры.viewDidAppear(_:)— ну, тут-то значения будут верные, но это ж как приехать на вокзал, когда поезд уже ушёл, ёпта! Вьюха уже на экране торчит, а ты только собрался её верстать. Поздно, пироги съедены.- И главный подвох —
viewDidLayoutSubviews()может дергаться дохуя раз: повернул экран, констрейнты поменял,setNeedsLayout()крикнул. Чтобы не настраивать интерфейс каждый раз, как идиот, используй флаг, ядрёна вошь:private var isFirstLayout = true override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if isFirstLayout { isFirstLayout = false // И вот тут делай свою магию один-единственный раз } }
Вот и вся наука. Не усложняй, блядь.