Могу ли я отключить автоматическое размещение для определенного подвида во время выполнения?

104

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

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

ужасная память
источник

Ответы:

168

У меня такая же проблема. Но я решил это.
Да, вы можете отключить автоматическую компоновку во время выполнения для определенного UIView, вместо того, чтобы отключать его для всего xib или раскадровки, которая установлена ​​по умолчанию в Xcode 4.3 и более поздних версиях.

Установите translatesAutoresizingMaskIntoConstraintsзначение YES, прежде чем устанавливать фрейм вашего подпредставления:

self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);
Мухаммад Аамир Али
источник
2
Это выглядит излишним для некоторых более сложных случаев с большим количеством просмотров. Для такой простой вещи это нормально.
esh
@MuhammadAamirAL Если удалить подпредставление, а затем добавить его обратно, это может снизить производительность. Можно ли заархивировать лучшее решение?
Nhat Dinh
2
@DinhNhat Я уточнил ответ. Удаление и повторное добавление подпредставления не требуется.
Леандрос
5
Он показывает мне предупреждение: «Невозможно одновременно удовлетворить ограничения».
NSPratik
1
Ты спас мне день ... переводит AutoresizingMaskIntoConstraints
Tintenklecks
50

У меня была аналогичная проблема, когда Autolayout переопределял некоторые из моих настроек кадра во время выполнения (у меня было динамическое представление, которое в некоторых случаях подталкивало новый контроллер представления ... нажатие, а затем нажатие Back приводило к сбросу исходного представления).

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

jmstone617
источник
1
Не работает для self.navigationItem.titleView. По-прежнему не уважает смену кадра.
Хенрик Эрландссон
1
Если вы пытаетесь испортить фрейм представления заголовка, я бы поместил его в представление контейнера и добавил представление контейнера как настраиваемое представление элемента навигации.
jmstone617
2
Это сработало и для меня. Я потратил 2 часа 22 минуты на то, чтобы удариться головой о стену из пословиц, прежде чем обнаружил этот обходной путь.
TMc
Спасибо чувак. Я уже второй день борюсь с этой проблемой, и теперь она работает!
апостолов
28

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

Джон Халл
источник
17

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

NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)

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

Или вы можете активировать / деактивировать с помощью removeConstraints и addConstraints.

Bandejapaisa
источник
Извините за захват такого старого вопроса, но могу ли я спросить, как вам вообще удалось добавить ограничения макета для разных макетов? Кажется, я не могу найти вариант внутри построителя интерфейса для включения / отключения ограничений. Или вы просто добавили ограничения для обоих макетов и просто проигнорировали построитель интерфейса, жалующийся на недопустимые (переопределяющие) ограничения?
Malte
Что ж, вы могли бы сделать это, используя классы размеров: developer.apple.com/library/ios/recipes/… , но я не мог сделать это таким образом, потому что я тоже поддерживал iOS 7, а классы размеров не полностью поддерживают iOS 7 Я сделал это, снизив приоритет конфликтующего ограничения. Не идеально, но предотвращает предупреждение. Думаю, я так и сделал ...
bandejapaisa
9

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

UIView + DisableAutolayoutTempoporary.h

#import <UIKit/UIKit.h>

@interface UIView (DisableAutolayoutTemporarily)

// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;

@end

UIView + DisableAutolayoutTempohibited.m

#import "UIView+DisableAutoResizeTemporarily.h"
@implementation UIView (DisableAutoResizeTemporarily)

- (void)resizeWithBlock:(void (^)(UIView * view))block
{
    UIView *superview = self.superview;
    [self removeFromSuperview];
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    __weak UIView *weakSelf = self;
    block(weakSelf);
    [superview addSubview:self];
}

@end

Я использую это так:

[cell.argumentLabel resizeWithBlock:^(UIView *view) {
    [view setFrame:frame];
}];

Надеюсь, поможет.

Майклсноуден
источник
Гениально! Я использовал модифицированную версию вашего кода, чтобы написать простую функцию "hideControl" для любого UIView. Он в основном устанавливает высоту UIView на 0, но, что особенно важно, он использует ваш код, чтобы AutoLayout обрабатывал его должным образом (в отличие от использования "someView.hidden = TRUE"). Таким образом, элементы управления, которые появлялись под скрытым элементом управления и имели связанный с ним вертикальный интервал, теперь сдвигались вверх по экрану, чтобы заполнить пробел, где ранее появлялся скрытый вид.
Майк Гледхилл
6

Вы можете установить translatesAutoresizingMaskIntoConstraintsтип Boolean, значение «Да» в определяемых пользователем атрибутах времени выполнения UIView, который вы хотите в xib / раскадровке.

Ренаун
источник
2
  • Открыть проект в 4.5
  • Выберите раскадровку
  • Откройте файловый инспектор
  • В документе Interface Builder снимите флажок «Использовать автоматическое размещение»

Вы можете разделить на несколько раскадровок, если хотите использовать автоматическое размещение для некоторых представлений.

Майк Боббитт
источник
10
Это отключает автоматическое размещение для всей раскадровки / пера. То, что я искал, - это способ (в идеале программный), чтобы определенные подпредставления в раскадровке / пере не использовали авто-раскладку, оставляя остальным делать то, что указано в раскадровке / пере.
ужасная
Вы можете использовать несколько раскадровок и просто вызывать те из них, которые имеют / не имеют автоматического раскладки по мере необходимости: // Инициализируйте контроллер раскадровки и детального представления для отображения UIStoryboard * sb = [UIStoryboard storyboardWithName: @ "Storyboard" bundle: [NSBundle mainBundle]]; DetailViewController * dvController = [sb instantiateViewControllerWithIdentifier: entry.viewName];
Майк Боббитт
1

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

Андреспч
источник
1

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

self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true
Большой D
источник
0

Это случилось со мной в проекте без раскадровки или файлов xib. Все 100% код. У меня был рекламный баннер внизу, и я хотел, чтобы границы просмотра ограничивались рекламным баннером. Размер представления изменится автоматически после загрузки. Я пробовал все разрешения на этой странице, но ни одно из них не помогло.

В итоге я просто создал подвид с укороченной высотой и поместил его в основной вид контроллера. Затем весь мой контент попал в подвид. Это очень легко решило проблему, не делая ничего, что казалось бы идущим против течения.

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

RandallTo
источник
0

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

  1. НЕ размещайте представления или компоненты в построителе интерфейса.

  2. Добавляйте свои представления чисто программно, начиная с alloc / init и соответствующим образом устанавливая их фреймы.

  3. Готово.

Ага.
источник
0

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

Например, если у вас есть вертикальное ограничение 0 между двумя представлениями (myView и otherView), и у вас есть жест панорамирования или что-то, что регулирует высоту myView, тогда вы можете пересчитать ограничение с настроенными значениями.

self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];
Майлз Кейли
источник
0

Для тех из вас, кто использует автоматический макет, ознакомьтесь с моим решением здесь . Вы должны создать @IBOutletограничения, которые хотите настроить, а затем изменить их константы.

Майк
источник
-16

если это файл xib:

  1. выберите файл .xib
  2. выберите "Владелец файла"
  3. показать Утилиты
  4. нажмите: «Инспектор файлов»
  5. В разделе «Документ разработчика интерфейса» отключите: «Использовать автоматическое размещение»
Алиш
источник
1
Нет, это отключает автоматическое размещение для всего xib. То, что я искал, - это способ убрать только одно конкретное подвид из системы автоматического размещения.
ужасная