Programmgesteuert CenterX / CenterY-Einschränkungen hinzufügen

84

Ich habe einen UITableViewController, der keine Abschnitte anzeigt, wenn nichts zu zeigen ist. Ich habe eine Beschriftung hinzugefügt, um dem Benutzer anzuzeigen, dass mit diesem Code nichts angezeigt werden kann:

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"
self.tableView.addSubview(label)

Aber jetzt möchte ich, dass es horizontal und vertikal zentriert wird. Normalerweise würde ich die beiden im Screenshot hervorgehobenen Optionen (plus diejenigen für Höhe und Breite) auswählen:

Geben Sie hier die Bildbeschreibung ein

Ich habe den folgenden Code versucht, um die Einschränkungen hinzuzufügen, aber die App stürzt mit einem Fehler ab:

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)

Error:

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

Das Etikett sollte immer horizontal und vertikal zentriert sein, da die App die Drehung des Geräts unterstützt.

Was mache ich falsch? Wie füge ich diese Einschränkungen erfolgreich hinzu?

Vielen Dank!

Mario A Guzman
quelle
2
Ich erstelle dies in VIDWDIDLOAD.
Mario A Guzman
2
Ich sehe die Zeile, in der Sie das Etikett als Unteransicht zu einer anderen Ansicht hinzufügen, nicht. Es ist wichtig, dass Sie dies tun, bevor Sie Einschränkungen hinzufügen.
Scott Berrevoets
Ich bin: label = UILabel (Frame: CGRectMake (20, 20, 250, 100)) label.text = "Nichts zu zeigen" self.tableView.addSubview (label)
Mario A Guzman

Antworten:

162

Update für Swift 3 / Swift 4:

Ab iOS 8 können und sollten Sie Ihre Einschränkungen aktivieren, indem Sie deren isActiveEigenschaft auf festlegen true. Dadurch können sich die Einschränkungen den richtigen Ansichten hinzufügen. Sie können mehrere Einschränkungen gleichzeitig aktivieren, indem Sie ein Array mit den Einschränkungen an übergebenNSLayoutConstraint.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])

Bessere Lösung:

Da diese Frage ursprünglich beantwortet wurde, wurden Layoutanker eingeführt, die das Erstellen der Einschränkungen erheblich vereinfachen. In diesem Beispiel erstelle ich die Einschränkungen und aktiviere sie sofort:

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

oder das gleiche mit 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)
])

Hinweis: Fügen Sie Ihre Unteransichten immer zur Ansichtshierarchie hinzu, bevor Sie die Einschränkungen erstellen und aktivieren.


Ursprüngliche Antwort:

Die Einschränkungen beziehen sich auf self.tableView. Da Sie die Bezeichnung als Unteransicht von hinzufügen self.tableView, müssen die Einschränkungen dem "gemeinsamen Vorfahren" hinzugefügt werden:

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

Wie @mustafa und @kcstricks in den Kommentaren betonten, müssen Sie festlegen label.translatesAutoresizingMaskIntoConstraints, dass false. Wenn Sie dies tun, müssen Sie auch das widthund heightdes Etiketts mit Einschränkungen angeben , da der Rahmen nicht mehr verwendet wird. Schließlich sollten Sie auch festlegen textAlignment, .Centerdass Ihr Text in Ihrer Beschriftung zentriert ist.

    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)
vacawama
quelle
Ausgezeichnet. Danke dir.
App Dev Guy
1
Die Anker haben für mich gearbeitet - ich schätze Ihre Mühe!
FullMetalFist
37

Im Behälter zentrieren

Geben Sie hier die Bildbeschreibung ein

Der folgende Code entspricht der Zentrierung im 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
    // ...
}

Methode 1: Ankerstil

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

Methode 2: NSLayoutConstraint-Stil

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

Anmerkungen

  • Der Ankerstil ist die bevorzugte Methode gegenüber dem NSLayoutConstraintStil. Er ist jedoch nur unter iOS 9 verfügbar. Wenn Sie also iOS 8 unterstützen, sollten Sie ihn weiterhin verwendenNSLayoutConstraint Stil verwenden.
  • Sie müssen auch Längen- und Breitenbeschränkungen hinzufügen.
  • Meine vollständige Antwort ist hier .
Suragch
quelle
10

Das ObjectiveC-Äquivalent lautet:

    myView.translatesAutoresizingMaskIntoConstraints = NO;

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

    [[myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];
Paul Gee
quelle
Beste für mich, Danke
Fadi Abuzant
8

Programmgesteuert können Sie dies tun, indem Sie die folgenden Einschränkungen hinzufügen.

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];
YaBoiSandeep
quelle
Bitte tauschen Sie ConstraintVertical gegen ConstraintHorizontal aus - es ist verwirrend
AlexeyVMP
5

In Swift 5 sieht es so aus:

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

Wenn Sie sich nicht dafür interessieren, dass es sich bei dieser Frage speziell um eine Tabellenansicht handelt, und Sie nur eine Ansicht über einer anderen Ansicht zentrieren möchten, gehen Sie wie folgt vor:

    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)
Adam Kalnas
quelle
1

Eine Lösung für mich war, ein zu erstellen UILabelund es UIButtonals Unteransicht hinzuzufügen. Schließlich habe ich eine Einschränkung hinzugefügt, um sie innerhalb der Schaltfläche zu zentrieren.

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; 
Coletrain
quelle