Программно Добавьте Ограничения CenterX/CenterY
У меня есть UITableViewController, который не отображает никаких разделов, если нет ничего, чтобы показать. Я добавил метку, чтобы указать пользователю, что с этим кодом нечего отображать:
label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"
self.tableView.addSubview(label)
Но теперь я хочу, чтобы он был центрирован по горизонтали и вертикали. Обычно я выбираю два варианта, выделенных (плюс один для высоты и ширины) на скриншоте:
Я попробовал следующий код, чтобы добавить ограничения, но приложение вылетает с ошибкой:
label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"
let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0)
label.addConstraint(xConstraint)
label.addConstraint(yConstraint)
Ошибка:
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2014-12-23 08:17:36.755 [982:227877] *** Assertion failure in -[UILabel _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /SourceCache/UIKit/UIKit-3318.16.21/NSLayoutConstraint_UIKitAdditions.m:560
Метка всегда должна располагаться по центру горизонтально и вертикально, поскольку приложение поддерживает вращение устройства.
Что я делаю не так? Как мне успешно добавить эти ограничения?
Спасибо!
5 ответов:
Обновление для Swift 3 / Swift 4:
Начиная с iOS 8, вы можете и должны активировать свои ограничения, установив их свойство
isActive
вtrue
. Это позволяет ограничениям добавлять себя в соответствующие представления. Вы можете активировать сразу несколько ограничений, передав массив, содержащий ограничения, вNSLayoutConstraint.activate()
let label = UILabel(frame: CGRect.zero) label.text = "Nothing to show" label.textAlignment = .center label.backgroundColor = .red // Set background color to see if label is centered label.translatesAutoresizingMaskIntoConstraints = false self.tableView.addSubview(label) let widthConstraint = NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 250) let heightConstraint = NSLayoutConstraint(item: label, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100) let xConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: self.tableView, attribute: .centerX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: self.tableView, attribute: .centerY, multiplier: 1, constant: 0) NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])
Лучшее Решение:
Поскольку на этот вопрос был первоначально дан ответ, были введены якоря компоновки, что значительно облегчило создайте ограничения. В этом примере я создаю ограничения и немедленно активирую их:
label.widthAnchor.constraint(equalToConstant: 250).isActive = true label.heightAnchor.constraint(equalToConstant: 100).isActive = true label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor).isActive = true label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor).isActive = true
Примечание: всегда добавляйте свои подвиды в иерархию представлений перед созданием и активацией ограничений.
Оригинальный Ответ:
Ограничения ссылаются на
self.tableView
. Поскольку вы добавляете метку в качестве подвидаself.tableView
, ограничения необходимо добавить к "общему предку":self.tableView.addConstraint(xConstraint) self.tableView.addConstraint(yConstraint)
Как @mustafa и @kcstricks указал в комментариях, что вам нужно установить
label.translatesAutoresizingMaskIntoConstraints
вfalse
. Когда вы делаете это, вам также нужно указатьwidth
иheight
метки с ограничениями, потому что фрейм больше не используется. Наконец, вы также должны установитьtextAlignment
в.Center
так, чтобы ваш текст был центрирован в вашей метке.var label = UILabel(frame: CGRectZero) label.text = "Nothing to show" label.textAlignment = .Center label.backgroundColor = UIColor.redColor() // Set background color to see if label is centered label.translatesAutoresizingMaskIntoConstraints = false self.tableView.addSubview(label) let widthConstraint = NSLayoutConstraint(item: label, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 250) label.addConstraint(widthConstraint) let heightConstraint = NSLayoutConstraint(item: label, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100) label.addConstraint(heightConstraint) let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0) self.tableView.addConstraint(xConstraint) self.tableView.addConstraint(yConstraint)
обновлено для 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 code for one of the constraint methods below // ... }
Метод 1: Якорный Стиль
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
Метод 2: Nslayoutconstraint Style
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0).active = true NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0).active = true
Примечания
- Anchor style является предпочтительным методом по сравнению со стилем
NSLayoutConstraint
, однако он доступен только в iOS 9, поэтому если вы поддерживаете iOS 8, вы все равно должны использоватьNSLayoutConstraint
стиль.- вам также потребуется добавить ограничения длины и ширины.
- мой полный ответ - здесь.
Программно это можно сделать, добавив следующие ограничения.
NSLayoutConstraint *constraintHorizontal = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:attribute multiplier:1.0f constant:0.0f]; NSLayoutConstraint *constraintVertical = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:attribute multiplier:1.0f constant:0.0f];
Эквивалент ObjectiveC:
myView.translatesAutoresizingMaskIntoConstraints = NO; [[myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES]; [[myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];
Если вы не заботитесь о том, чтобы этот вопрос был конкретно о tableview, и вы просто хотели бы центрировать один вид поверх другого вида, вот что нужно сделать:
let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: parentView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0) parentView.addConstraint(horizontalConstraint) let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: parentView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0) parentView.addConstraint(verticalConstraint)