Создание программных ограничений компоновки
Я знаю, что многие люди уже задавали тонны вопросов об этом, но даже с ответами я не могу заставить его работать.
Когда я имею дело с ограничениями на раскадровку, это легко, но в коде мне тяжело.
Я пытаюсь, например, иметь представление, которое остается с правой стороны и имеет высоту экрана в соответствии с ориентацией экрана. Это мой код:
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
?
Ответы
Ответ 1
При использовании автоматической компоновки в коде установка кадра ничего не делает. Поэтому тот факт, что вы указали ширину 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 viewview имеет минимальную высоту из 748 пунктов. ширина myView равна 200pts и имеет правильное дополнение, равное стандартное пространство против его наблюдения.
Если вы просто хотите, чтобы представление заполнило всю высоту супервизора без ограничения высоты супервизора, вы просто опустите параметр (>=748)
в текст визуального формата. Если вы считаете, что параметр (>=748)
необходим для того, чтобы дать ему высоту - в этом случае вы не должны: привязать представление к краям супервизора с помощью панели (|
) или строки с пробелом (|-
, -|
), вы даете вашему представлению y-позицию (фиксируя представление на одном краю) и y-позицию с высотой (привязывая представление к обоим краям), тем самым удовлетворяя вашему ограничению, установленному для представления.
В отношении вашего второго вопроса:
Используя NSDictionaryOfVariableBindings(self.myView)
(если у вас была настройка свойств для myView) и загрузите его в свой VFL, чтобы использовать self.myView
в тексте VFL, вы, вероятно, получите исключение, когда autolayout попытается проанализировать ваш текст VFL. Это связано с точечным обозначением в словарных клавишах и системой, пытающейся использовать valueForKeyPath:
. См. здесь похожие вопросы и ответы.
Ответ 2
Привет, я много использовал эту страницу для ограничений и "как". Мне потребовалось бесконечно, чтобы понять, что мне нужно:
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)]];
Ответ 3
Быстрая версия
Обновлен для 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
Style, однако он доступен только для iOS 9, поэтому, если вы поддерживаете iOS 8, вы должны использовать NSLayoutConstraint
Style.
- См. также документацию Programmatically Creating Constraints.
- См. этот ответ для аналогичного примера добавления ограничения пиннинга.
Ответ 4
Что касается вашего второго вопроса о свойствах, вы можете использовать self.myView
, только если вы объявили его как свойство в классе. Поскольку myView
является локальной переменной, вы не можете использовать ее таким образом. Для получения дополнительной информации об этом, я бы порекомендовал вам пройти документацию по яблоку в Объявленные свойства,
Ответ 5
Почему я не могу использовать свойство типа self.myView
вместо локальной переменной, например myView?
попробуйте использовать:
NSDictionaryOfVariableBindings(_view)
вместо self.view
Ответ 6
Также обратите внимание, что из iOS9 мы можем программно "ограничить" программными "более краткими и более легкими для чтения" с использованием подклассов нового вспомогательного класса NSLayoutAnchor.
Пример из документа:
[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;