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


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, поэтому пользователь ничего не понимает.


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.


Извините за захват такого старого вопроса, но могу ли я спросить, как вам вообще удалось добавить ограничения макета для разных макетов? Кажется, я не могу найти вариант внутри построителя интерфейса для включения / отключения ограничений. Или вы просто добавили ограничения для обоих макетов и просто проигнорировали построитель интерфейса, жалующийся на недопустимые (переопределяющие) ограничения?
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

0

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

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

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


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. То, что я искал, - это способ убрать только одно конкретное подвид из системы автоматического размещения.
ужасная
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.