Я установил несколько наборов ограничений в IB, и я хотел бы программно переключаться между ними в зависимости от некоторого состояния. Есть constraintsA
коллекция розеток, все из которых помечены как установленные из IB, и constraintsB
коллекция розеток, все из которых удалены в IB.
Я могу программно переключаться между двумя наборами следующим образом:
NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)
Но ... я не могу понять, когда это сделать. Кажется, я смогу сделать это один раз viewDidLoad
, но я не могу заставить это работать. Я пробовал позвонить view.updateConstraints()
и view.layoutSubviews()
после установки ограничений, но безуспешно.
Я обнаружил, что если я установлю ограничения, viewDidLayoutSubviews
все будет работать так, как ожидалось. Думаю, я хотел бы знать две вещи ...
- Почему у меня такое поведение?
- Можно ли активировать / деактивировать ограничения из viewDidLoad?
ios
swift
uiview
autolayout
nslayoutconstraint
tybro0103
источник
источник
Ответы:
Активирую и деактивирую
NSLayoutConstraints
вviewDidLoad
, и у меня с этим проблем нет. Так что это работает. Должна быть разница в настройке вашего приложения и моего :-)Я просто опишу свою настройку - может быть, это поможет вам:
@IBOutlets
все ограничения, которые мне нужно активировать / деактивировать.ViewController
, я сохраняю ограничения в свойствах класса, которые не являются слабыми. Причина этого в том, что я обнаружил, что после деактивации ограничения я не мог повторно активировать его - оно было равно нулю. Значит, при деактивации вроде удаляется.NSLayoutConstraint.deactivate/activate
как вы, я используюconstraint.active = YES
/NO
вместо.view.layoutIfNeeded()
.источник
.active = false
ожидая, что они будут проигнорированы, пока я не установлю их в активное состояние.Может быть, вы могли бы проверить свой
@properties
, заменитьweak
наstrong
.Иногда это потому , что он
active = NO
установленself.yourConstraint = nil
, чтобы вы не могли использовать егоself.yourConstraint
снова.источник
weak
и это будет сделано.источник
Я считаю, что проблема, с которой вы столкнулись, связана с тем, что ограничения не добавляются к их представлениям до вызова AFTER
viewDidLoad()
. У вас есть несколько вариантов:A) Вы можете подключить свои ограничения макета к IBOutlet и получить к ним доступ в своем коде по этим ссылкам. Поскольку розетки подключаются перед
viewDidLoad()
запуском, ограничения должны быть доступны, и вы можете продолжать активировать и деактивировать их там.B) Если вы хотите использовать
constraints()
функцию UIView для доступа к различным ограничениям, вы должны дождатьсяviewDidLayoutSubviews()
начала и сделать это там, поскольку это первая точка после создания контроллера представления из пера, в котором будут установлены какие-либо ограничения. Не забудьте позвонить,layoutIfNeeded()
когда закончите. У этого есть недостаток, заключающийся в том, что проход макета будет выполняться дважды, если есть какие-либо изменения, которые нужно применить, и вы должны убедиться, что нет возможности запуска бесконечного цикла.Небольшое предупреждение: отключенные ограничения НЕ возвращаются
constraints()
методом! Это означает, что если вы ДЕЙСТВИТЕЛЬНО отключите ограничение с намерением снова включить его позже, вам нужно будет сохранить ссылку на него.C) Вы можете забыть о раскадровке и вместо этого добавить свои ограничения вручную. Поскольку вы делаете это,
viewDidLoad()
я предполагаю, что намерение состоит в том, чтобы сделать это только один раз за все время существования объекта, а не изменять макет на лету, поэтому это должен быть приемлемый метод.источник
Вы также можете настроить
priority
свойство, чтобы «включить» и «отключить» их (например, значение 750 для включения и 250 для отключения). По какой-то причине изменениеactive
BOOL не повлияло на мой интерфейс. Нет необходимости вlayoutIfNeeded
и может быть установлен и изменен в viewDidLoad или в любое время после этого.источник
viewWillTransition(to:, with:)
или,viewWillLayoutSubviews()
и вы можете оставить все свои альтернативные ограничения как «установленные» в раскадровке. Приоритет ограничения не может измениться с необязательного на обязательный, поэтому используйте значения ниже1000
. С другой стороны, активация (добавление) и деактивация (удаление) ограничений работает только вviewDidLayoutSubviews()
и требует сохраненияstrong
@IBOutlet
ссылок наNSLayoutConstraint
-s.Подходящее время для деактивации неиспользуемых ограничений:
Имейте в виду, что это
viewWillLayoutSubviews
может быть вызвано несколько раз, так что никаких сложных вычислений, хорошо?Примечание: если вы хотите отреагировать на некоторые из ограничений позже, всегда сохраняйте
strong
ссылку на них.источник
viewDidLayoutSubviews()
. ВviewWillLayoutSubviews()
моем случае настройка ограничений не работает.При создании представления по порядку вызываются следующие методы жизненного цикла:
Теперь к вашим вопросам.
Ответ: Потому что, когда вы пытаетесь установить ограничения для представлений, в
viewDidLoad
представлении нет своих границ, следовательно, ограничения не могут быть установлены. Только послеviewDidLayoutSubviews
этого границы представления окончательно определены.Ответ: Нет. Причина объяснена выше.
источник
Я обнаружил, что до тех пор, пока вы устанавливаете ограничения в соответствии с нормой в переопределении
- (void)updateConstraints
(цель c), соstrong
ссылкой на начальное значение используемых активных и неактивных ограничений. А в другом месте цикла просмотра деактивируйте и / или активируйте то, что вам нужно, а затем позвонитеlayoutIfNeeded
, у вас не должно возникнуть проблем.Главное - не постоянно повторно использовать переопределение
updateConstraints
и разделять активации ограничений, если вы вызываетеupdateConstraint
s после первой инициализации и макета. После этого, кажется, имеет значение, где именно в цикле просмотра.источник