Ответ 1
Существуют две недоиспользуемые функции построителя интерфейса Xcode, которые мы можем использовать здесь, чтобы сделать синхронизацию такого рода.
- Вы можете создать
IBOutlet
соединения дляNSLayoutConstraints
. - Вы можете подключить "коллекцию розетки", которая представляет собой массив объектов
IBOutlet
.
Итак, имея в виду эти две вещи, суть того, что мы хотим сделать, - это создать все наши ограничения автоопределения для одной ориентации, объединить их в сборку. Теперь для каждого из этих ограничений снимите флажок "Установленный" в построителе интерфейса. Затем сделайте все наши коллекции для другого макета и подключите их к другой коллекции. Мы можем создать столько групп макетов, сколько хотим.
Важно отметить, что нам понадобится ссылка на любой элемент пользовательского интерфейса, который имеет ограничения, установленные на нем напрямую, и нам потребуется отдельная коллекция розетки не только для каждого макета, который мы хотим, но и для каждого объекта пользовательского интерфейса, у которого установлены ограничения на нем напрямую.
Посмотрим на довольно упрощенный пример из вашего вопроса.
Если вы посмотрите в списке ограничений слева, вы увидите, что половина из них выделена серым цветом. Скрытые ограничения - это ограничения ландшафта. Я создал все из них, а затем снял флажок "Установил" для каждого из них:
Между тем, нераскрытые, нормальные взгляды ограничивают портретные ограничения. Для этого я оставил их "Установлен". Нет необходимости оставлять какие-либо из них, но вы столкнетесь с проблемами, если оставите несколько установленных наборов (они скорее всего конфликтуют).
Обязательно не проверяйте "Удалить во время сборки" для любого из них. Мы не хотим, чтобы ограничения были "удалены" во время сборки. Это просто означает, что ограничение вообще не создано (поэтому мы потеряем ссылку на него). Если оставить эту отметку отмеченной, пока у нас есть ограничение IBOutlet
, Xcode будет генерировать предупреждение:
Неподдерживаемая конфигурация
Подключение к ограничению заполнителя. Ограничения, отмеченные как заполнители в IB, не должны иметь никаких соединений, поскольку эти ограничения не компилируются в документ и не будут существовать во время выполнения.
В любом случае, теперь нам нужно подключить ограничения к розетке, чтобы мы могли получить к ним доступ во время выполнения.
Удерживайте Ctrl и щелкните и перетащите из одного из ограничений в файл исходного кода, так же, как вы подключите любой другой элемент пользовательского интерфейса. В появившемся диалоговом окне выберите Outlet Collection и описательное имя:
Теперь подключите все другие ограничения, которые соответствуют этой группе ограничений, в один и тот же набор:
Как только мы закончим подключение всех наших ограничений, это просто вопрос удаления/добавления их в соответствующее время.
Для такого простого примера, как сценарий, описанный в вопросе, мы можем переопределить updateViewConstraints
следующим кодом:
Swift
class ViewController: UIViewController {
@IBOutlet var landscapeConstraints: [NSLayoutConstraint]!
@IBOutlet var portraitConstraints: [NSLayoutConstraint]!
override func updateViewConstraints() {
let isPortrait = self.view.bounds.width < self.view.bounds.height
self.view.removeConstraints(self.portraitConstraints)
self.view.removeConstraints(self.landscapeConstraints)
self.view.addConstraints(isPortrait ? self.portraitConstraints : self.landscapeConstraints)
super.updateViewConstraints()
}
}
Objective-C
@interface ViewController()
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints;
@end
@implementation ViewController
- (void)updateViewConstraints {
BOOL isPortrait = self.view.bounds.size.width < self.view.boudns.size.height;
[self.view removeConstraints:self.portraitConstraints];
[self.view removeConstraints:self.landscapeConstraints];
[self.view addConstraints:(isPortrait ? self.portraitConstraints : self.landscapeConstraints)];
[super updateViewConstraints];
}
@end
Мы не проверяем, какой набор ограничений был ранее рассмотрен, поэтому просто удалите оба наших набора ограничений, а затем добавьте соответствующий набор, который мы хотим использовать.
Это весь код, который нам нужен, чтобы полностью изменить весь набор ограничений для объекта во время выполнения. Это позволяет работать в построителе интерфейса, чтобы установить все наши ограничения, вместо того, чтобы делать это программно (что я считаю немного более утомительным и подверженным ошибкам).
Конечный результат? Очень красиво выглядящая перегруппировка авторотации, не вытягивая ваши волосы, получая код автоопределения, выполненный отлично: