Разберитесь в методах, которые вызываются для представления наших представлений.
Сложность: Начинающий | Легко | Нормальный | Испытывающий
Предпосылки
- Некоторое понимание объектно-ориентированного программирования было бы полезно.
Основной цикл выполнения приложения для iOS
Apple включила iOS SDK для обработки пользовательских событий и запуска ответов в приложении с помощью очереди событий.
Когда пользователь взаимодействует с приложением, событие добавляется в очередь событий, которая затем может быть обработана приложением и потенциально отправлена другим объектам в приложении. После обработки событий они возвращают управление основному циклу выполнения и начинают цикл обновления, который отвечает за компоновку и рисование видов.
Цикл обновления
Как только управление возвращается в основной цикл выполнения, система визуализирует макет в соответствии с ограничениями экземпляров представления.
Когда представление помечено как требующее изменения в следующем цикле обновления, система выполняет все изменения.
Система работает через цикл выполнения, затем ограничения перед переходом отложенного макета.
Отложенный проход макета
Ограничения обычно создаются во время создания контроллера представления (возможно, в функции viewDidLoad()
).
Однако во время выполнения динамические изменения ограничений не сразу принимаются системой. К сожалению, изменение останется в устаревшем состоянии, ожидая следующего отложенного прохода макета и - на самом деле, этого может никогда не произойти. Пользователь просматривает устаревшее представление. Ужасный.
Точно так же другие изменения объектов (например, изменение свойств элемента управления) также могут изменять ограничения для других объектов, потенциально приводя к той же проблеме.
Решение этой проблемы - запросить отложенную передачу макета, вызвав setNeedsLayout()
в соответствующем представлении (или setNeedsUpdateConstraints()
).
Технически отложенный проход верстки (по документации) включает два прохода:
- При необходимости этап обновления обновляет ограничения. Это вызывает метод
updateViewConstraints
для всех контроллеров представления и методupdateConstraints
для всех представлений. - При необходимости на этапе макета кадры вида меняются. Это вызывает
viewWillLayoutSubviews
для всех контроллеров представления иlayoutSubviews
для каждого представления.
Соответствующие методы? Они находятся прямо ниже, но более подробно рассматриваются в статье.
Риск бесконечных циклов
Мы помещаем представления в список, чтобы запросить обновление отложенного прохода макета. Риск этого заключается в том, что на каждом проходе будет выполняться еще один запрос на отложенный проход макета.
- Всегда вызывайте суперкласс при переопределении метода.
- Не звоните
setNeedsLayout()
внутриlayoutSubviews
. - Не звоните
setNeedsUpdateConstraints()
внутриupdateConstraints()
.
Принудительно перерисовать с помощью setNeedsDisplay
setNeedsDisplay()
вызывает перерисовку определенного вида. Поскольку вы никогда не должны вызывать draw(_ rect: CGRect)
напрямую, вы можете думать о setNeedsDisplay()
как о методе запроса UIKit на перерисовку. Другой способ думать об этом заключается в том, что при вызове setNeedsDisplay()
представление помечается как грязное; то есть в следующем цикле обновления представление будет перерисовано через отложенный проход макета.
Так как проход отложен, он произойдет во время следующего цикла обновления, в течение которого func draw(_:)
будет вызываться для всех таких представлений.
Новичка это немного сбивает с толку, так как большинство компонентов пользовательского интерфейса позаботятся об этом за нас. Однако может быть свойство, которое не связано напрямую с компонентом пользовательского интерфейса, и нам нужно сообщить Swift о том, что к чему, с помощью нашего вызова.
Макет триггера обновляется с помощью setNeedsLayout
Когда вид изменяется, макет изменяется, и для этого требуется пересчет с помощью Auto Layout.
Обычно макет обновляется автоматически. То есть, когда размер представления изменяется, он добавляется в иерархию представления, ограничения обновляются, а устройство поворачивается или пользователь выполняет прокрутку.
Бывают ситуации, когда нам нужно принудительно пересчитать макет конкретного экземпляра представления. и они охватываются следующей парой методов.
setNeedsLayout ()
setNeedsLayout()
запрашивает обновление макета для определенного вида. Это произойдет в следующем цикле обновления, который из-за быстрого обновления экранов устройств iOS должен быть достаточно быстрым, чтобы пользователь не испытывал никаких задержек.
layoutIfNeeded ()
Это похоже на layoutIfNeeded()
в том, что вызывает немедленное обновление макета. Один конкретный случай, когда это используется, - это анимация ограничений, которую из-за анимации необходимо обновить немедленно.
layoutSubview
Метод layoutSubview
вызывается при изменении размера представления, в том числе при его первой установке. Это означает, что переопределение этого было бы подходящим местом для установки радиуса угла UIView или аналогичного.
Вместо того, чтобы быть вызванным напрямую, он запускается системой, когда представление сначала выкладывается (то есть при первом отрисовке), а также при повороте. Его можно запросить с помощью setNeedsLayout()
для следующего обновления чертежа или принудительно сразу с помощью layoutIfNeeded()
.
Если вы работаете в контроллере представления viewDidLayoutSubviews()
, можно использовать аналогичный метод здесь.
Обновить ограничения
При обновлении представлений вызывается метод func draw(_ rect: CGRect)
(если он есть).
Не используйте updateConstraints()
для начальной настройки представления. Используйте его для максимальной производительности, когда вам нужно добавить, изменить или удалить множество ограничений за один проход макета. Но на практике обычно имеет смысл поменять их на месте в любом случае. Таким образом, могут быть причины для повышения производительности для использования этого метода, но в целом этого не следует делать.
UpdateConstraints
также имеет родственную функцию для viewController
, updateViewConstraints()
, что может быть полезно.
Понимание координат
Понимание того, как обновляется представление и как оно соотносится с методами в UIView, необходимо для вашего пути в качестве разработчика, ориентированного на Swift.
Координаты для любого конкретного UIView начинаются в верхнем левом углу, как показано на следующей диаграмме:
Заключение
В UIKit использование представлений чрезвычайно важно. Есть довольно много того, что нужно понять и к чему нужно привыкнуть, но важно понять концепции, которые помогут вам на вашем пути в качестве разработчика.
Расширьте свои знания
- Прочтите Документацию Apple о концепциях рисования.
- У Apple есть документация по отложенному макету.