Удаление ограничений автоматического компоновки для конкретного объекта

У меня есть UIImageView, встроенный в UIView. Все мое приложение использует AutoLayout, но я хочу удалить constraints для UIImageView. Xcode не позволит мне удалить constraints, есть ли способ отключить их для определенного объекта, установить их в ноль, что-то?

Ответ 1

Я согласен, что автокоманда Xcode ужасна для использования, если вы хотите что-то конкретное...

Что я использую для автоматического удаления ограничений:

[detailsPhotoView removeConstraints:detailsPhotoView.constraints];

Ответ 2

В XCode 5 есть опция во время редактирования ограничений "Удалить во время сборки". Если это разрешено, ограничение будет автоматически удалено во время выполнения. Опция заключается в том, чтобы поддерживать интерфейс Builder счастливым, если вы не хотите конкретных ограничений.

Ответ 3

Здесь есть два различных вопроса:

  • Как использовать Xcode для настройки UIImageView без ограничений.
  • Как разрешить UIImageView настраивать и/или изменять размер, когда его макет обрабатывается ограничениями.

Относительно (1), jturton является правильным. Пока вы включили автоматическую компоновку в Xcode, Xcode гарантирует/требует, чтобы были достаточные ограничения для уникального определения размера и местоположения вашего представления.

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

Если у UIImageView не было никаких ограничений, его макет не определялся, поэтому вы не можете установить это в Xcode. Чтобы исправить это, вам нужно использовать Xcode для настройки IBOutlets ко всем ограничениям, которые вы хотите удалить, а затем в своем UIView awakeFromNib: или в вашем UIViewController viewDidLoad: вы вручную удаляете ограничения, вызывая removeConstraints:.

Однако теперь ваш макет UIImageView недоопределен. Поэтому в этот момент вам нужно вручную добавить новые ограничения, которые позволят вам перемещать и изменять размер UIImageView, что приводит нас к вопросу (2).

Относительно (2), как изменить размер и перемещать представление, макет которого определяется ограничениями, ответ заключается в настройке распознавателей жестов, как обычно, для обнаружения жестов прижимания и панорамирования, но вместо этих распознавателей жестов, вызывающих setFrame: для изменения в представлении они должны изменить параметр constant NSLayoutConstraint, который определяет кадр UIImageView, а затем вызывает layoutIfNeeded:, который заставит систему макета немедленно перевести это модифицированное ограничение в новый фрейм.

Итак, предположим, вы хотите манипулировать UIImageView с помощью набора ограничений макета, которые были очень похожи на знакомые вызовы setFrame: calls. В этом случае после удаления настроек ограничений с помощью Xcode вы можете добавить ограничения к виду, которые определяют его ширину, ее высоту и ее пространство сверху и слева от супервизора. Затем обработчик действия для вашего распознавателя жестов будет просто обновлять постоянный параметр распознавателя жестов pacer, а ваш распознаватель жестов может просто обновлять постоянный параметр ограничений высоты и ширины.

Другой способ сделать (2), который является таким же под капотом, но может быть проще на практике, заключается в установке translatesAutoresizingMaskIntoConstraints=YES. Это будет делать две вещи. Это заставит автоматическую систему компоновки автоматически генерировать ограничения в представлении viewview на основе вида autoresizingMask. Второе - крайне важно! - это приведет к тому, что система макета автоматически переводит вызовы на setFrame: в модификации этих ограничений.

Ответ 4

У вас не может быть ограничений - у вас должно быть достаточно ограничений для однозначного размера и размещения каждого представления

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

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

Вы также можете создавать ограничения размера по горизонтали и по вертикали. См. Мой ответ здесь о том, как это сделать. Создайте выходные данные для этих двух ограничений (если используется построитель интерфейса). Вы можете иметь ограничения по высоте и ширине определенного числа или использовать множитель для фиксированного соотношения сторон.

В ответ на жесты щепотки вы можете настроить свойства .constant двух ограничений размера и вызвать setNeedsLayout. Это изменит размер вашего изображения, сохраняя при этом его центр.

Если вы сделаете предложение с фиксированным соотношением сторон выше, изменение размера представления с использованием ограничений на самом деле намного проще, чем установка фрейма.

Ответ 5

вы можете позвонить

[yourElement removeFromSuperview];

а затем вызовите

[yourSuperview addSubview:yourElement];

чтобы удалить все ограничения из yourElement и добавить его обратно в представление.

Стоит отметить, что если вы делаете это выше, например, в категории UIView или расширении, вам нужно сохранить ссылку на супервизор вида перед удалением из супервизора:

var theSuperview = self.superview
self.removeFromSuperview()
theSuperview?.addSubview(self)

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

Ответ 6

Если вы просто хотите удалить представление из иерархии, просто вызовите [theView removeFromSuperview]. Любые ограничения, влияющие на него, также будут удалены.

Однако иногда вы также можете поместить представление назад, удалив его временно.

Для этого я использую следующую категорию на UIView. Он просматривает иерархию представлений из представления v в некоторый конечный вид контейнера c (обычно это ваш корневой вид контроллера представления) и удаляет ограничения, внешние по отношению к v. Это ограничения, которые являются братьями и сестрами v, а не ограничения, которые влияют только на детей v. Вы можете скрыть v.

-(NSArray*) stealExternalConstraintsUpToView: (UIView*) superview
{
    NSMutableArray *const constraints = [NSMutableArray new];

    UIView *searchView = self;
    while(searchView.superview && searchView!= superview)
    {
        searchView = searchView.superview;

        NSArray *const affectingConstraints =
        [searchView.constraints filteredArrayUsingPredicate:
         [NSPredicate predicateWithBlock:^BOOL(NSLayoutConstraint *constraint, NSDictionary *bindings)
          {
              return constraint.firstItem == self || constraint.secondItem == self;
          }]];

        [searchView removeConstraints: affectingConstraints];
        [constraints addObjectsFromArray: affectingConstraints];
    }

    return constraints;
}

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

Используйте это немного как это...

NSArray *const removedConstraints = [viewToHide stealExternalConstraintsUpToView: self.view];
[viewToHide setHidden: YES];

И позже, верните ограничения.

Как и в iOS 8, вам не нужно думать о том, где должны быть установлены ограничения. Просто используйте это...

[NSLayoutConstraint activateConstraints: removedConstraints];
[viewToHide setHidden: NO];

В более ранних версиях iOS вам не нужно много думать о том, где добавить ограничения. Затем бросьте в контроллер self.view. При условии, что ограничения находятся в a супервизии всех видов, на которые они влияют, они будут работать.

[self.view addConstraints: removedConstraints];
[viewToHide setHidden: NO];