Я знаю, что цепочка автоматической разметки состоит в основном из 3 различных процессов.
- Обновление ограничений
- макеты просмотров (вот где мы получаем расчет кадров)
- дисплей
Что мне не совсем понятно, так это внутренняя разница между -setNeedsLayout
и -setNeedsUpdateConstraints
. Из Apple Docs:
Вызывайте этот метод в главном потоке вашего приложения, если вы хотите настроить макет подпредставлений представления. Этот метод записывает запрос и сразу же возвращается. Поскольку этот метод не вызывает немедленного обновления, а вместо этого ожидает следующего цикла обновления, его можно использовать для аннулирования макета нескольких представлений до обновления любого из этих представлений. Такое поведение позволяет консолидировать все обновления макета в один цикл обновления, что обычно лучше для производительности.
Когда свойство вашего пользовательского представления изменяется таким образом, что это повлияет на ограничения, вы можете вызвать этот метод, чтобы указать, что ограничения должны быть обновлены в какой-то момент в будущем. Затем система вызовет updateConstraints как часть обычного прохода макета. Одновременное обновление ограничений непосредственно перед тем, как они понадобятся, гарантирует, что вы не будете без необходимости пересчитывать ограничения, когда в ваши представления вносятся множественные изменения между проходами макета.
Когда я хочу анимировать представление после изменения ограничения и анимировать изменения, которые я обычно вызываю, например:
[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self.modifConstrView setNeedsUpdateConstraints];
[self.modifConstrView layoutIfNeeded];
} completion:NULL];
Я обнаружил, что если я использую -setNeedsLayout
вместо того, чтобы -setNeedsUpdateConstraints
все работало, как ожидалось, но если я изменился -layoutIfNeeded
с -updateConstraintsIfNeeded
, анимация не произойдет.
Я попытался сделать свой собственный вывод:
-updateConstraintsIfNeeded
только обновляет ограничения, но не вынуждает макет войти в процесс, таким образом, оригинальные кадры все еще сохраняются-setNeedsLayout
вызывает также-updateContraints
метод
Итак, когда можно использовать один вместо другого? и о методах макета, нужно ли мне вызывать их в представлении, которое имеет изменение в ограничении, или в родительском представлении?
Ответы:
Ваши выводы верны. Основная схема:
setNeedsUpdateConstraints
удостоверится, что будущий звонок наupdateConstraintsIfNeeded
звонкиupdateConstraints
.setNeedsLayout
удостоверится, что будущий звонок наlayoutIfNeeded
звонкиlayoutSubviews
.Когда
layoutSubviews
вызывается, он также вызываетupdateConstraintsIfNeeded
, поэтому, по моему опыту, вызов этого вручную редко требуется. На самом деле, я никогда не вызывал его, за исключением случаев отладки макетов.Обновление ограничений с использованием
setNeedsUpdateConstraints
довольно редко, objc.io - обязательное чтение об автопоставках - говорит :Кроме того, по моему опыту, мне никогда не приходилось аннулировать ограничения и не устанавливать
setNeedsLayout
в следующей строке кода, потому что новые ограничения в значительной степени требуют нового макета.Эмпирические правила:
setNeedsLayout
.updateConstraints
методе (рекомендуемый способ изменить ограничения, кстати), вызовsetNeedsUpdateConstraints
и большую часть времениsetNeedsLayout
после этого.layoutIfNeeded
.Кроме того, я полагаю, что в вашем коде анимации нет необходимости
setNeedsUpdateConstraints
, поскольку ограничения обновляются перед анимацией вручную, и анимация только отображает представление на основе различий между старым и новым.источник
setNeedsLayout
.setNeedsLayout
гарантирует, чтоlayoutSubviews
будет вызван в следующем цикле обновления, но, возможно, это не имеет ничего общего сlayoutIfNeeded
?layoutSubviews
будет вызываться автоматически, звонить не нужноsetNeedsLayout
layoutSubviews
, поэтому нет необходимости делать это вручную. ОднакоlayoutIfNeeded
вам нужно позвонить, если вам нужно, чтобы изменения вступили в силу немедленно, а не в следующем цикле макетаОтвет на coverback довольно правильно. Тем не менее, я хотел бы добавить некоторые дополнительные детали.
Ниже приведена схема типичного цикла UIView, который объясняет другое поведение:
-setNeedsLayout
вместо того, чтобы-setNeedsUpdateConstraints
все работало, как ожидалось, но если я изменился-layoutIfNeeded
с-updateConstraintsIfNeeded
, анимация не произойдет.updateConstraints
обычно ничего не делает Он просто разрешает ограничения, но не вызывает их, пока неlayoutSubviews
будет вызван. Так что анимация требует вызоваlayoutSubviews
.Нет, это не обязательно. Если ваши ограничения не были изменены, UIView пропустит вызов
updateConstraints
. Вам нужно явно позвонить,setNeedsUpdateConstraint
чтобы изменить ограничения в процессе.Для звонка
updateConstraints
необходимо сделать следующее:источник