setNeedsLayout против setNeedsUpdateConstraints и layoutIfNeeded против updateConstraintsIfNeeded
Я знаю, что цепочка автоматической компоновки состоит в основном из 3 разных процессов.
- ограничения обновления
- вид макета (здесь мы получаем расчет рамы)
- дисплей
что мне не совсем понятно, так это внутренняя разница между -setNeedsLayout
и -setNeedsUpdateConstraints
. Из Документов Apple:
называем это метод в главном потоке вашего приложения, когда вы хотите настройте макет подвидов вида. Этот метод делает примечание: запрос и немедленно возвращается. Потому что этот метод не принудительное немедленное обновление, но вместо этого ждет следующего обновления цикл, вы можете использовать его для аннулирования макета нескольких представлений перед обновлением любого из этих представлений. Такое поведение позволяет консолидируйте все обновления макета в один цикл обновления, который обычно лучше спектакль.
когда свойство вашего пользовательского представления изменяется таким образом, что это повлияет ограничения, можно вызвать этот метод, чтобы указать, что ограничения необходимо обновить в какой-то момент в будущем. Тогда система вызов 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
метод
Итак, когда можно использовать один вместо другого? и о методах макета, нужно ли вызывать их в представлении, которое имеет изменение ограничения или в Родительском представлении?
2 ответов
ваши выводы правильны. базовая схема:
-
setNeedsUpdateConstraints
гарантирует будущий вызовupdateConstraintsIfNeeded
звонкиupdateConstraints
. -
setNeedsLayout
гарантирует будущий вызовlayoutIfNeeded
звонкиlayoutSubviews
.
, когда layoutSubviews
называется, он также называет updateConstraintsIfNeeded
, поэтому вызов его вручную редко требуется в моем опыте. На самом деле, я никогда не вызывал его, кроме как при отладке макетов.
обновление ограничений с помощью setNeedsUpdateConstraints
тоже довольно редко,objc.io-a должен прочитать об autolayouts-говорит:
если что-то изменится позже, что аннулирует одно из ваших ограничений, вы должны немедленно удалить ограничение и вызвать setNeedsUpdateConstraints. на самом деле, это единственный случай, когда вам нужно запустить проход обновления ограничений.
кроме того, по моему опыту, мне никогда не приходилось аннулировать ограничения и не устанавливать the setNeedsLayout
в следующей строке кода, потому что новые ограничения в значительной степени запрашивают новый макет.
эмпирические правила:
- если вы непосредственно манипулировали ограничениями, вызовите
setNeedsLayout
. - если вы изменили некоторые условия (например, смещения или smth), которые б изменить ограничения в переопределенном
updateConstraints
метод (рекомендуемый способ изменения ограничений, кстати), вызовsetNeedsUpdateConstraints
, и большую часть времениsetNeedsLayout
после что. - Если вам нужно какое-либо из действий выше, чтобы иметь немедленный эффект-например, когда вам нужно узнать новую высоту кадра после прохождения макета-добавьте его с
layoutIfNeeded
.
кроме того, в вашем коде анимации, я считаю setNeedsUpdateConstraints
не требуется, так как ограничения обновляются перед анимацией вручную, а анимация только повторно выкладывает представление, основанное на различиях между старыми и новыми.
ответ coverback довольно правильный . Однако, я хотел бы добавить некоторые дополнительные детали.
Ниже приведена диаграмма типичного цикла UIView, которая объясняет другие поведения
- я узнал, что если я использую-setNeedsLayout вместо-setNeedsUpdateConstraints, все работает так, как ожидалось, но если я изменю-layoutIfNeeded с-updateConstraintsIfNeeded, анимация не будет случаться.
updateConstraints
обычно ничего не делает. Он просто разрешает ограничения, которые он не применяет до layoutSubviews
называется. Таким образом, анимация требует вызова layoutSubviews
.
- setNeedsLayout также вызывает-updateContraints метод
нет это не надо. Если ваши ограничения не были изменены, UIView пропустит вызов updateConstraints
. Вам нужно явно вызвать setNeedsUpdateConstraint
для изменения ограничений в процесс.
для того, чтобы позвонить updateConstraints
вам нужно сделать следующее :
[view setNeedsUpdateConstraints];
[view setNeedsLayout];
[view layoutIfNeeded];