setNeedsLayout против setNeedsUpdateConstraints и layoutIfNeeded против updateConstraintsIfNeeded

Я знаю, что цепочка автоматической компоновки состоит в основном из 3 разных процессов.

  1. ограничения обновления
  2. вид макета (здесь мы получаем расчет рамы)
  3. дисплей

что мне не совсем понятно, так это внутренняя разница между -setNeedsLayout и -setNeedsUpdateConstraints. Из Документов Apple:

setNeedsLayout

называем это метод в главном потоке вашего приложения, когда вы хотите настройте макет подвидов вида. Этот метод делает примечание: запрос и немедленно возвращается. Потому что этот метод не принудительное немедленное обновление, но вместо этого ждет следующего обновления цикл, вы можете использовать его для аннулирования макета нескольких представлений перед обновлением любого из этих представлений. Такое поведение позволяет консолидируйте все обновления макета в один цикл обновления, который обычно лучше спектакль.

setNeedsUpdateConstraints

когда свойство вашего пользовательского представления изменяется таким образом, что это повлияет ограничения, можно вызвать этот метод, чтобы указать, что ограничения необходимо обновить в какой-то момент в будущем. Тогда система вызов 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, которая объясняет другие поведения UIView's Lifecycle

  1. я узнал, что если я использую-setNeedsLayout вместо-setNeedsUpdateConstraints, все работает так, как ожидалось, но если я изменю-layoutIfNeeded с-updateConstraintsIfNeeded, анимация не будет случаться.

updateConstraints обычно ничего не делает. Он просто разрешает ограничения, которые он не применяет до layoutSubviews называется. Таким образом, анимация требует вызова layoutSubviews.

  1. setNeedsLayout также вызывает-updateContraints метод

нет это не надо. Если ваши ограничения не были изменены, UIView пропустит вызов updateConstraints. Вам нужно явно вызвать setNeedsUpdateConstraint для изменения ограничений в процесс.

для того, чтобы позвонить updateConstraints вам нужно сделать следующее :

   [view setNeedsUpdateConstraints];
   [view setNeedsLayout];
   [view layoutIfNeeded];