Создание ограничений макета программно


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

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

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 83

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

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

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

enter image description here

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

enter image description here

стандартный код

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;