Програмно додавати обмеження CenterX / CenterY


84

У мене є 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

Етикетка завжди повинна бути по центру горизонтально та вертикально, оскільки програма підтримує обертання пристрою.

Що я роблю не так? Як мені успішно додати ці обмеження?

Дякую!


2
Я СТВОРЮЮ ЦЕ В ПЕРЕГЛЯДІ.
Mario A Guzman

2
Я не бачу рядка, де ви додаєте мітку як підпрогляд до якогось іншого подання. Важливо зробити це перед тим, як додавати до нього обмеження.
Скотт Берреєць,

Я: label = UILabel (кадр: CGRectMake (20, 20, 250, 100)) label.text = "Нічого не показувати" self.tableView.addSubview (label)
Mario A Guzman

Відповіді:


163

Оновлення для 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

або те саме, використовуючи NSLayoutConstraint.activate():

NSLayoutConstraint.activate([
    label.widthAnchor.constraint(equalToConstant: 250),
    label.heightAnchor.constraint(equalToConstant: 100),
    label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor),
    label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor)
])

Примітка: Завжди додайте свої підпрограми до ієрархії подань перед створенням та активацією обмежень.


Оригінальна відповідь:

Обмеження посилаються на 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)

Відмінно. Дякую.
App Dev Guy

1
якорі працювали на мене - я ціную ваші зусилля!
FullMetalFist

37

Відцентруйте в контейнері

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

У наведеному нижче коді зроблено те саме, що і центрування в Interface Builder.

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

NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true

Примітки

  • Стиль прив'язки є кращим методом порівняно зі NSLayoutConstraintСтилем, однак він доступний лише з iOS 9, тому, якщо ви підтримуєте iOS 8, вам все одно слід використовувати NSLayoutConstraintStyle.
  • Вам також потрібно буде додати обмеження довжини та ширини.
  • Моя повна відповідь тут .

10

Еквівалент ObjectiveC:

    myView.translatesAutoresizingMaskIntoConstraints = NO;

    [[myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES];

    [[myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];

найкращий для мене, дякую
Фаді Абузант

8

Програмно це можна зробити, додавши такі обмеження.

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];

Будь ласка, поміняйте
місцями

5

У Swift 5 це виглядає так:

label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor).isActive = true

1

Якщо вам байдуже, що це питання стосується конкретно табличного перегляду, і ви просто хочете, щоб один вигляд був центрований на іншому, ось для цього:

    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)

1

Рішенням для мене було створити UILabelта додати його до UIButtonпідпрогляду. Нарешті, я додав обмеження, щоб відцентрувати його в межах кнопки.

UILabel * myTextLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 75, 75)];
myTextLabel.text = @"Some Text";
myTextLabel.translatesAutoresizingMaskIntoConstraints = false;

[myButton addSubView:myTextLabel];

// Add Constraints
[[myTextLabel centerYAnchor] constraintEqualToAnchor:myButton.centerYAnchor].active = true;
[[myTextLabel centerXAnchor] constraintEqualToAnchor:myButton.centerXAnchor].active = true; 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.