ActivateConstraints: and deactivateConstraints: не сохраняется после вращения для ограничений, созданных в IB

Новые методы NSLayoutConstraint activateConstraints: и deactivateConstraints: не работают корректно с ограничениями, создаваемыми IB (они корректно работают для ограничений, созданных кодом). Я создал простое тестовое приложение с одной кнопкой, которая имеет два набора ограничений. Один установленный набор имеет ограничения по центру и центру, а другой набор, который удаляется, имеет верхние и левые ограничения (константа 10). Метод кнопки переключает эти наборы ограничений. Вот код,

@interface ViewController ()
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *uninstalledConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints;
@end

@implementation ViewController


- (IBAction)switchconstraints:(UIButton *)sender {
    [NSLayoutConstraint deactivateConstraints:self.installedConstraints];
    [NSLayoutConstraint activateConstraints:self.uninstalledConstraints];
}


-(void)viewWillLayoutSubviews {
    NSLog(@"installed: %@    uninstalled: %@", ((NSLayoutConstraint *)self.installedConstraints[0]).active ? @"Active" : @"Inactive", ((NSLayoutConstraint *)self.uninstalledConstraints[0]).active ? @"Active" : @"Inactive");

}

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

Вопрос в том, является ли это ошибкой или эти методы не должны работать таким образом с определенными ограничениями IB?

Ответ 1

Проблема в том, что вы делаете что-то несогласованное с "неустановленными" ограничениями в раскадровке. Они там, но не там. Ограничения "Uninstalled" предназначены только для классов размера! Вы используете их, если вы решите, что ограничения на преобразование Xcode будут автоматически установлены при вращении. Xcode не может справиться с тем, что вы делаете. Но если вы создадите второй набор ограничений в коде, все будет нормально работать.

Итак, сделайте это. Удалите два "неустановленных" ограничения и удалите выход uninstalledConstraints. Теперь замените весь код контроллера просмотра следующим образом:

@property (strong, nonatomic) NSMutableArray *c1;
@property (strong, nonatomic) NSMutableArray *c2;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints;
@property (weak,nonatomic) IBOutlet UIButton *button;
@end

@implementation ViewController {
    BOOL did;
}

- (void)viewDidLayoutSubviews {
    NSLog(@"did");
    if (!did) {
        did = YES;
        self.c1 = [self.installedConstraints mutableCopy];
        self.c2 = [NSMutableArray new];
        [self.c2 addObject:
         [NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1 constant:30]];
        [self.c2 addObject:
         [NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeadingMargin multiplier:1 constant:30]];
    }
}

- (IBAction)switchconstraints:(UIButton *)sender {
    [NSLayoutConstraint deactivateConstraints:self.c1];
    [NSLayoutConstraint activateConstraints:self.c2];
    NSMutableArray* temp = self.c1;
    self.c1 = self.c2;
    self.c2 = temp;
}

Теперь несколько раз нажмите кнопку. Как вы видите, он прыгает между двумя позициями. Теперь поверните приложение; кнопка остается там, где она есть.

Ответ 2

Я столкнулся с подобной ситуацией.

Я создал два набора NSLayoutConstraints в построителе интерфейса. Каждый набор для одного случая. Один набор был "установлен" другим.

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

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

Btw: Strang я использовал "установленный/не установлен" aproach на другом контроллере view, их работа сработала.

В нерабочем случае viewcontroller был встроен в contenterview, возможно, именно по этой причине.

Ответ 3

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

Хитрость заключается в том, чтобы не удалять ограничения (как указывал @matt), а деактивировать их в viewDidLoad() вашего подкласса UIViewController, прежде чем макет возникнет (и ваши конфликтующие ограничения вызывают проблему).

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