Где изменить "установлен" для ограничения автоматической компоновки?

При использовании автоматической компоновки в раскадровке существует опция установки установленного ограничения или нет с помощью флажка "Установлено". Отключение его приведет к тому, что он будет вести себя так, как если бы вы не добавили это ограничение - он не будет иметь никакого эффекта. Вы можете настроить установленное состояние для разных классов размера в Interface Builder, и вы можете изменить это значение программно, установив его свойство active в true или false.

В моем приложении я хочу установить ограничение только в том случае, если устройство находится на портрете - оно должно быть "удалено" при повороте в альбомное. Это можно сделать для iPhones, сняв флажок, установленный для Any Width Compact Height. (Хотя, похоже, это работает не так, потому что это нарушает это ограничение из-за противоречивых ограничений при повороте в ландшафт, когда его даже не нужно устанавливать, но независимо от того, что пользовательский интерфейс всегда выглядит так, как ожидалось.) Но нет способа удалить ограничение для iPad в ландшафте в Interface Builder (это регулярная ширина обычной высоты в обеих ориентациях).

Где подходящее место для включения/выключения active для NSLayoutConstraint при вращении устройства? В каком способе поворота будет изменен этот статус в результате желаемого поведения - будет установлен только для портрета? Если этот метод не вызван при запуске приложения, в каком другом методе он должен быть помещен в дополнение к методу вращения?

Я попытался разместить следующий код в viewDidLoad и viewWillTransitionToSize, но это приводит к неожиданному поведению при работе на iPad:

  • Запуск приложения в ландшафте приводит к тому, что ограничение должно быть активным, несмотря на то, что активный параметр был установлен в false, он прерывает ограничение, и пользовательский интерфейс не отображается как ожидалось
  • Запуск приложения в портретных наборах активен в true (он уже был установлен в IB), поэтому он работает как ожидалось
  • Запуск приложения в портрете и поворот устройства в альбомное работает как ожидалось - ограничение установлено на неактивное, оно не нарушает ограничение, пользовательский интерфейс отображается как ожидалось
  • Запуск приложения в портрете, поворот на пейзаж и возврат к портрету приводит к правильному отображению пользовательского интерфейса, но он нарушает это ограничение, которое установлено на активный

Если я удалю ограничение в Interface Builder, тогда запустите указанные выше сценарии, я получаю по существу противоположное поведение.

if size.width > size.height {
    self.myConstraint.active = false
} else {
    self.myConstraint.active = true
}

Ответ 1

Я немного опоздал, но вот мои 2 цента, когда я столкнулся с аналогичной проблемой, чтобы решить проблему неспособности Autolayout обнаружить Compact Width/Compact Height для iPhone с iOS 7. В iOS 7 нет свойства activated, поэтому мне пришлось добавлять/удалять их.

Я создал два метода для добавления и удаления ограничений, и эти ограничения уже установлены на IB, и я ссылаюсь на их свойства IBOutlet. Поэтому, поскольку я удаляю их, в отличие от других объектов IB, я должен установить их в strong, а не weak. В противном случае, как только я их удалю, они будут уничтожены, и я не смогу ссылаться на них еще раз, чтобы повторно добавить их.

Вот мой метод удаления ограничений:

-(void)removeiOS7andiPhone4inLandscapeToOrientation:(UIInterfaceOrientation)toInterfaceOrientation{

    if( !UIInterfaceOrientationIsLandscape(toInterfaceOrientation )&&(NSFoundationVersionNumber<=NSFoundationVersionNumber_iOS_7_1)&&( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone )){
         // if iPhone with iOS 7 on portrait remove Constraints here

    }
}

и вот метод сумматора ограничений:

-(void)addiOS7andiPhone4inLandscapeToOrientation:(UIInterfaceOrientation)toInterfaceOrientation{

    if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation )&&(NSFoundationVersionNumber<=NSFoundationVersionNumber_iOS_7_1)&&( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone )){
       // if iPhone with iOS 7 on landscape add Constraints here

    }

}

Как для вызова этих методов, как вы пробовали, вызовите оба из них в viewWillAppear (нет необходимости звонить в viewWillDisappear) и viewWillTransitionToSize (в моем случае это willRotateToInterfaceOrientation, так как viewWillTransitionToSize доступен только после iOS 8). Вызов их впоследствии имеет смысл, ведь только один из них будет запущен из-за проверки их портретной/альбомной ориентации с помощью if, прежде чем вносить необходимые изменения.

и вот мое определение метода willRotateToInterfaceOrientation:

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

    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    // this will be run only if orientation is on Portrait
    [self addiOS7andiPhone4inLandscapeToOrientation:toInterfaceOrientation];

    // this will be run only if orientation is on Landscape
    [self removeiOS7andiPhone4inLandscapeToOrientation:toInterfaceOrientation];
}

и выполните аналогичный вызов в viewWillAppear.

УВЕДОМЛЕНИЕ: убедитесь, что в этих методах вы выполняете точную противоположность, и вы не обязательно добавляете ограничения только в addConstraintMethod и удаляете только в removeConstraintMethod. В моем случае я добавляю и удаляю ограничения в каждом из них, поэтому наименование методов точно не отражает их истинную роль, но пока вы делаете точные противоположности, вам хорошо идти.