Подтвердить что ты не робот

Как изменить порядок просмотров при авторотации с автозагрузкой?

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

Для упрощенного примера рассмотрим следующее:

Портрет:

MkdAR.jpg

Пейзаж:

FSgFd.jpg

Обратите внимание на то, что в портрете изображения уложены вертикально, но в ландшафте они бок о бок?

Конечно, я могу вручную вычислять позиции и размеры, но для более сложных представлений это быстро становится сложным. Кроме того, я бы предпочел использовать Autolayout, чтобы там был меньше кода, специфичного для устройства (если он вообще есть). Но это похоже на много кода Autolayout для записи. Есть ли способ установить ограничения для такого рода материалов через раскадровку?

4b9b3361

Ответ 1

Существуют две недоиспользуемые функции построителя интерфейса Xcode, которые мы можем использовать здесь, чтобы сделать синхронизацию такого рода.

  • Вы можете создать IBOutlet соединения для NSLayoutConstraints.
  • Вы можете подключить "коллекцию розетки", которая представляет собой массив объектов IBOutlet.

Итак, имея в виду эти две вещи, суть того, что мы хотим сделать, - это создать все наши ограничения автоопределения для одной ориентации, объединить их в сборку. Теперь для каждого из этих ограничений снимите флажок "Установленный" в построителе интерфейса. Затем сделайте все наши коллекции для другого макета и подключите их к другой коллекции. Мы можем создать столько групп макетов, сколько хотим.

Важно отметить, что нам понадобится ссылка на любой элемент пользовательского интерфейса, который имеет ограничения, установленные на нем напрямую, и нам потребуется отдельная коллекция розетки не только для каждого макета, который мы хотим, но и для каждого объекта пользовательского интерфейса, у которого установлены ограничения на нем напрямую.

Посмотрим на довольно упрощенный пример из вашего вопроса.

enter image description here

Если вы посмотрите в списке ограничений слева, вы увидите, что половина из них выделена серым цветом. Скрытые ограничения - это ограничения ландшафта. Я создал все из них, а затем снял флажок "Установил" для каждого из них:

enter image description here

Между тем, нераскрытые, нормальные взгляды ограничивают портретные ограничения. Для этого я оставил их "Установлен". Нет необходимости оставлять какие-либо из них, но вы столкнетесь с проблемами, если оставите несколько установленных наборов (они скорее всего конфликтуют).

enter image description here

Обязательно не проверяйте "Удалить во время сборки" для любого из них. Мы не хотим, чтобы ограничения были "удалены" во время сборки. Это просто означает, что ограничение вообще не создано (поэтому мы потеряем ссылку на него). Если оставить эту отметку отмеченной, пока у нас есть ограничение IBOutlet, Xcode будет генерировать предупреждение:

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

В любом случае, теперь нам нужно подключить ограничения к розетке, чтобы мы могли получить к ним доступ во время выполнения.

Удерживайте Ctrl и щелкните и перетащите из одного из ограничений в файл исходного кода, так же, как вы подключите любой другой элемент пользовательского интерфейса. В появившемся диалоговом окне выберите Outlet Collection и описательное имя:

enter image description here

Теперь подключите все другие ограничения, которые соответствуют этой группе ограничений, в один и тот же набор:

enter image description here

Как только мы закончим подключение всех наших ограничений, это просто вопрос удаления/добавления их в соответствующее время.

Для такого простого примера, как сценарий, описанный в вопросе, мы можем переопределить 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

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

Это весь код, который нам нужен, чтобы полностью изменить весь набор ограничений для объекта во время выполнения. Это позволяет работать в построителе интерфейса, чтобы установить все наши ограничения, вместо того, чтобы делать это программно (что я считаю немного более утомительным и подверженным ошибкам).

Конечный результат? Очень красиво выглядящая перегруппировка авторотации, не вытягивая ваши волосы, получая код автоопределения, выполненный отлично:

NY04qXR.gif

Ответ 2

Теперь, когда UIStackView доступен в iOS9, более простым и гарантированным решением было бы добавить оба представления в стеке, связать представление стека с IBOutlet, а затем добавить следующий код в диспетчер представлений:

- (void) adjustViewsForOrientation:(UIInterfaceOrientation) orientation {

if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown || orientation == UIInterfaceOrientationUnknown)
    self.stackView.axis = UILayoutConstraintAxisVertical;
else
    self.stackView.axis = UILayoutConstraintAxisHorizontal;

[self.stackView setNeedsLayout];
[self.stackView setNeedsDisplay];

}

и вызовите этот метод из

-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration