Programowo Dodawaj Ograniczenia CenterX/CenterY

Mam Kontroler UITableViewController, który nie wyświetla żadnych sekcji, jeśli nie ma nic do pokazania. Dodałem etykietę, aby wskazać użytkownikowi, że nie ma nic do wyświetlenia z tym kodem:

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"
self.tableView.addSubview(label)
Ale teraz chcę, żeby było wyśrodkowane poziomo i pionowo. Normalnie wybrałbym dwie opcje podświetlone (plus te dla wysokości i szerokości) na zrzucie ekranu:

Tutaj wpisz opis obrazka

Próbowałem poniższego kodu, aby dodać ograniczenia, ale aplikacja zawiesza się z błędem:

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)

Błąd:

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

Etykieta powinna być zawsze wyśrodkowana poziomo i pionowo, ponieważ aplikacja obsługuje obrót urządzenia.

Co robię źle? Jak skutecznie dodać te ograniczenia? Dzięki!
Author: jww, 2014-12-23

5 answers

Aktualizacja dla Swift 3/Swift 4:

Od wersji iOS 8 Możesz i powinieneś aktywować swoje ograniczenia, ustawiając ich Właściwość isActive na true. Dzięki temu ograniczenia mogą dodawać się do odpowiednich widoków. Możesz aktywować wiele ograniczeń jednocześnie, przekazując tablicę zawierającą ograniczenia do 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])

Lepsze Rozwiązanie:

Ponieważ pierwotnie udzielono odpowiedzi na to pytanie, wprowadzono kotwice układu, co znacznie ułatwia twórz ograniczenia. W tym przykładzie tworzę ograniczenia i natychmiast je aktywuję:

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

Uwaga: Przed utworzeniem i aktywacją ograniczeń zawsze Dodawaj swoje podwidywacze do hierarchii widoków .


Oryginalna Odpowiedź:

Ograniczenia odnoszą się do self.tableView. Ponieważ dodajesz etykietę jako podgląd podrzędny self.tableView, ograniczenia muszą być dodane do"wspólnego przodka":

   self.tableView.addConstraint(xConstraint)
   self.tableView.addConstraint(yConstraint)

Jako @ mustafa i @kcstricks wskazał w komentarzach, musisz ustawić label.translatesAutoresizingMaskIntoConstraints na false. Gdy to zrobisz, musisz również określić width i height etykiety z ograniczeniami, ponieważ ramka nie jest już używana. Na koniec należy również ustawić textAlignment na .Center, aby tekst był wyśrodkowany w etykiecie.

    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)
 86
Author: vacawama,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 14:32:29

Aktualizacja dla Swift 3

Środek w pojemniku

Tutaj wpisz opis obrazka

Poniższy kod robi to samo, co centrowanie w Kreatorze interfejsów.

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
    // ...
}

Metoda 1: Anchor Style

myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Metoda 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

Uwagi

  • styl kotwicy jest preferowaną metodą w stosunku do stylu NSLayoutConstraint, Jednak jest ona dostępna tylko z iOS 9, więc jeśli obsługujesz iOS 8, powinieneś nadal używać NSLayoutConstraint Style.
  • należy również dodać ograniczenia długości i szerokości.
  • Moja pełna odpowiedź to tutaj .
 26
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:13

Programowo można to zrobić, dodając następujące ograniczenia.

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];
 8
Author: YaBoiSandeep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-13 04:22:54

Odpowiednikiem ObjectiveC jest:

    myView.translatesAutoresizingMaskIntoConstraints = NO;

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

    [[myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];
 8
Author: Paul Gee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-26 18:23:33

Jeśli nie zależy ci na tym, aby to pytanie dotyczyło widoku tabeli, a chciałbyś wyśrodkować jeden widok na inny widok, to zrób to:

    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
Author: Adam Kalnas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-05 20:38:50