Программное создание ограничений макета

84

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

Когда я имею дело с ограничениями на раскадровке, это легко, но с кодом мне трудно. Я пытаюсь, например, иметь представление, которое остается с правой стороны и имеет высоту экрана в соответствии с ориентацией экрана. Это мой код:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Он не удовлетворяет некоторым ограничениям. Я не вижу, что не так. Кроме того, почему я не могу использовать свойство like self.myViewвместо локальной переменной типа myView?

Pierre23
источник
Что такое vivi в приведенном выше коде?
iDev
14
Измените заголовок на «iOS» вместо «IOS» - последнее относится к операционной системе коммутатора / маршрутизатора Cisco. Смутил меня. Благодарю.
armani
1
Несколько вопросов по этому поводу: (1) Какую ошибку вы получаете, когда "не удовлетворяет некоторым ограничениям"? (2) Вы переводите автоматическое изменение размеров в ограничения myView? (3) Что vivi(как спросил ACB)? (4) Есть ли у вас myViewзаявленная недвижимость self?
Тим
1
ih Тим, извини, vivi, я слишком быстро нажал кнопку ... это myView. Что вы имеете в виду под переводом? Все, что я делаю, это код выше. Что касается свойства, у меня есть несколько других представлений, которые объявляются как свойство, но когда я реализую тот же код для этого свойства, происходит сбой ... сообщение «ошибка» действительно большое, я не могу вставить его сюда
pierre23
Чтобы временно удалить ограничения из определенного представления, сделайте следующее: stackoverflow.com/questions/13388104/…
Sam B

Ответы:

106

При использовании Auto Layout в коде установка рамки ничего не делает. Таким образом, тот факт, что вы указали ширину 200 в представлении выше, ничего не значит, когда вы устанавливаете для него ограничения. Чтобы набор ограничений представления был однозначным, ему нужны четыре вещи: позиция по оси x, позиция по оси y, ширина и высота для любого заданного состояния.

В настоящее время в приведенном выше коде у вас есть только два (высота относительно супервизора и y-позиция относительно супервизора). В дополнение к этому у вас есть два обязательных ограничения, которые могут конфликтовать в зависимости от того, как установлены ограничения супервизора представления. Если суперпредставление должно иметь обязательное ограничение, указывающее, что его высота будет некоторым значением меньше 748, вы получите исключение «невыполнимые ограничения».

Тот факт, что вы установили ширину представления перед установкой ограничений, ничего не значит. Он даже не будет принимать во внимание старый фрейм и вычислит новый фрейм на основе всех ограничений, которые он указал для этих представлений. Имея дело с автоматическим размещением в коде, я обычно просто создаю новое представление, используя initWithFrame:CGRectZeroили просто init.

Чтобы создать набор ограничений, необходимый для макета, который вы устно описали в своем вопросе, вам нужно будет добавить несколько горизонтальных ограничений, чтобы ограничить ширину и положение по оси x, чтобы получить полностью определенный макет:

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Устное описание этого макета звучит следующим образом, начиная с ограничения по вертикали:

myView заполнит высоту своего супервизора верхним и нижним отступом, равным стандартному пространству. Минимальная высота супервизора myView составляет 748 точек. Ширина myView составляет 200 точек и имеет правое заполнение, равное стандартному пространству для его супервизора.

Если вы просто хотите, чтобы представление заполняло всю высоту супервизора без ограничения высоты супервизора, то вы просто опустите (>=748)параметр в тексте визуального формата. Если вы считаете, что (>=748)параметр необходим для присвоения ему высоты - в данном случае вы этого не делаете: закрепляя представление на краях супервизора с помощью синтаксиса bar ( |) или bar с пробелом ( |-, -|), вы даете своему представлению y -position (закрепление вида на одном краю) и y-положение с высотой (закрепление вида на обоих краях), таким образом удовлетворяя ваши ограничения, установленные для вида.

Что касается вашего второго вопроса:

Используя NSDictionaryOfVariableBindings(self.myView)(если у вас была настройка свойств для myView) и вводя это в ваш VFL для использования self.myViewв вашем тексте VFL, вы, вероятно, получите исключение, когда autolayout попытается проанализировать ваш текст VFL. Это связано с точечной нотацией в ключах словаря и системой, которую пытается использовать valueForKeyPath:. См. Здесь аналогичный вопрос и ответ .

ларсак
источник
Не забывайте, что некоторые объекты, такие как UILabel, имеют внутренний размер, и вам не нужно устанавливать ширину или высоту этого объекта, только его положение. Однако, если вы установите высоту или ширину, я считаю, что они удаляют и то, и другое, и вам нужно указать оба.
Ник Тернер
Хотя этот ответ не дал ответа на мой вопрос, он помог мне кое-что понять. Спасибо за присутствие! :)
Матей
1
Единственное краткое и удобочитаемое введение автоматического макета в Интернете на данный момент.
Джои Карсон
пожалуйста, помогите мне, мой вопрос
61

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

myView.translatesAutoresizingMaskIntoConstraints = NO;

чтобы этот пример заработал. Спасибо Userxxx, Робу М. и особенно larsacus за объяснение и код здесь, это было бесценно.

Вот полный код для запуска приведенных выше примеров:

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];
BriOnH
источник
11

Свифт версия

Обновлено для Swift 3

В этом примере будут показаны два метода для программного добавления следующих ограничений так же, как если бы это было сделано в Интерфейсном Разработчике:

Ширина и высота

введите описание изображения здесь

Центр в контейнере

введите описание изображения здесь

Код шаблона

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

Метод 1: стиль привязки

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Метод 2: стиль NSLayoutConstraint

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

Ноты

  • Стиль привязки является предпочтительным методом по сравнению со NSLayoutConstraintстилем, однако он доступен только в iOS 9, поэтому, если вы поддерживаете iOS 8, вам все равно следует использовать NSLayoutConstraintстиль.
  • См. Также документацию по программному созданию ограничений .
  • См. Этот ответ для аналогичного примера добавления ограничения закрепления.
Suragch
источник
5

Что касается вашего второго вопроса о свойствах, вы можете использовать, self.myViewтолько если вы объявили его как свойство в классе. Поскольку myViewэто локальная переменная, вы не можете использовать ее таким образом. Чтобы получить более подробную информацию об этом, я бы порекомендовал вам просмотреть документацию Apple по объявленным свойствам ,

iDev
источник
5

почему я не могу использовать свойство, например, self.myViewвместо локальной переменной, например myView?

попробуйте использовать:

NSDictionaryOfVariableBindings(_view)

вместо self.view

Мегариш
источник
Это приводит к сбою моего приложения, выдает сообщение: «Невозможно проанализировать формат ограничения: polylineImageView не является ключом в словаре представлений».
Тай Ле
4

Также обратите внимание, что в iOS9 мы можем программно определять ограничения «более кратко и легче для чтения», используя подклассы нового вспомогательного класса NSLayoutAnchor .

Пример из документа:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
Andreacipriani
источник