Создание ограничений макета программно
Я знаю, что многие люди уже задавали тонны вопросов об этом, но даже с ответами я не могу заставить его работать.
когда я имею дело с ограничениями на раскадровке, это легко, но в коде у меня есть трудное время. Я пытаюсь, например, иметь вид, который остается на правой стороне и имеет высоту экрана в соответствии с ориентацией экрана. Это мой код:
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)]];
Он не удовлетворяет некоторым ограничениям. Я не вижу, что случилось. Кроме того, почему я не могу использовать свойство типа self.myView
вместо локальной переменной, как myView
?
6 ответов:
при использовании автоматической компоновки в коде установка рамки ничего не делает. Так что тот факт, что вы указали ширину 200 на вид выше, ничего не значит, когда вы устанавливаете ограничения на него. Чтобы набор ограничений представления был однозначным, ему нужны четыре вещи: x-позиция, y-позиция, ширина и высота для любого заданного состояния.
в настоящее время в коде выше, у вас есть только два (высота, относительно супервизора, и y-положение, относительно супервизора). В кроме того, у вас есть два обязательных ограничения, которые могут конфликтовать в зависимости от того, как настроены ограничения супервизора представления. если супервизор должен был иметь обязательное ограничение, которое указывает, что его высота будет некоторым значением меньше 748, вы получите исключение "unsatisfiable constraints".
тот факт, что вы установили ширину представления перед установкой ограничений, ничего не значит. Он даже не будет учитывать старый кадр и рассчитает новый фрейм основан на всех ограничениях, которые он задал для этих представлений. При работе с autolayout в коде я обычно просто создаю новое представление с помощью
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 имеет минимальную высоту из 748pts. ширина myView составляет 200pts и имеет правую прокладку, равную стандартное пространство против его супервизора.
если бы вы просто хотели, чтобы вид заполнял всю высоту супервизора, не ограничивая высоту супервизора, то вы бы просто опустите
(>=748)
параметр в тексте визуального формата. Если вы думаете, что(>=748)
параметр требуется, чтобы дать ему высоту - вы не в этом случае: закрепление вида к краям супервизора с помощью панели (|
) или бар с пространством (|-
,-|
) синтаксис, вы даете вашему виду y-позицию (закрепление вида на одном краю) и y-позицию с высотой (закрепление вида на обоих краях), тем самым удовлетворяя вашему набору ограничений для вида.в отношении ваш второй вопрос:
используя
NSDictionaryOfVariableBindings(self.myView)
(если у вас была настройка свойств для myView) и подача этого в ваш VFL для использованияself.myView
в вашем тексте VFL вы, вероятно, получите исключение, когда autolayout попытается проанализировать ваш текст VFL. Это связано с точечной нотацией в ключах словаря и системой, пытающейся использоватьvalueForKeyPath:
. смотрите здесь аналогичный вопрос и ответ.
Привет я использую эту страницу много для ограничений и"как". Мне потребовалась вечность, чтобы понять, что мне нужно:
myView.translatesAutoresizingMaskIntoConstraints = NO;
чтобы заставить этот пример работать. Спасибо Userxxx, Rob M. и особенно 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)]];
Swift версия
обновлено для 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 Style
// 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
стиль.- см. также Программное Создание Ограничений документация.
- посмотреть этот ответ для аналогичного примера добавления ограничения закрепления.
что касается вашего второго вопроса о свойствах, вы можете использовать
self.myView
только если вы объявили его как свойство в классе. Так какmyView
является локальной переменной, вы не можете использовать его таким образом. Для получения более подробной информации об этом, я бы рекомендовал вам пройти через документацию apple на Заявленные Свойства,
почему я не могу использовать свойство типа
self.myView
вместо локальной переменной типа myView?попробуйте использовать:
NSDictionaryOfVariableBindings(_view)
вместо
self.view
обратите внимание, что из iOS9 мы можем определить ограничения программно "более лаконично, и легче читать" использование подклассов нового вспомогательного класса NSLayoutAnchor.
пример из документа:
[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;