2014-12-23 3 views
28

Ho un UITableViewController che non visualizza alcuna sezione se non c'è nulla da mostrare. Ho aggiunto un'etichetta per indicare all'utente che non c'è nulla da visualizzare con questo codice:Aggiungi limiti CenterX/CenterY

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

Ma ora, io voglio che sia centrato orizzontalmente e verticalmente. Normalmente, vorrei scegliere le due opzioni evidenziate (più quelli per altezza e larghezza) nella schermata:

enter image description here

Ho provato il seguente codice per aggiungere i vincoli, ma l'applicazione si blocca con l'errore:

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) 

errore:

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 

l'etichetta deve sempre centrare orizzontalmente e verticalmente perché l'applicazione supporta rotazione il dispositivo.

Cosa sto sbagliando? Come posso aggiungere questi vincoli con successo?

Grazie!

+2

IO SONO CREATO QUESTO IN VIEWDIDLOAD. –

+2

Non vedo la riga in cui si aggiunge l'etichetta come sottoview ad un'altra vista. È importante farlo prima di aggiungere vincoli ad esso. –

+0

I am: label = UILabel (frame: CGRectMake (20, 20, 250, 100)) label.text = "Niente da mostrare" self.tableView.addSubview (etichetta) –

risposta

50

Aggiornamento per Swift 3/Swift 4:

Come di iOS 8, si può e deve attivare le costrizioni impostando le loro proprietà isActive a true. Ciò consente ai vincoli di aggiungersi alle viste corrette. È possibile attivare più vincoli contemporaneamente passando un array contenente i vincoli per 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]) 

soluzione migliore:

Poiché tale questione è stato originariamente risposto, sono stati introdotti ancore di layout rendendo molto più facile per creare il vincoli. In questo esempio creo i vincoli e immediatamente li attivare:

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 

Nota: aggiungere sempre le subviews alla gerarchia vista prima la creazione e l'attivazione dei vincoli.


risposta originale:

I vincoli fanno riferimento a self.tableView. Dal momento che si sta aggiungendo l'etichetta come una visualizzazione secondaria di self.tableView, i vincoli devono essere aggiunti al "antenato comune":

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

Come @mustafa e @kcstricks sottolineato nei commenti, è necessario impostare label.translatesAutoresizingMaskIntoConstraints a false. Quando si esegue questa operazione, è inoltre necessario specificare width e height dell'etichetta con i vincoli poiché il frame non viene più utilizzato. Infine, devi anche impostare textAlignment su .Center in modo che il testo sia centrato nell'etichetta.

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) 
+0

Eccellente. Grazie. –

8

A livello di codice è possibile farlo aggiungendo i seguenti vincoli.

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

Si prega di scambiare vincoloVertical con constraintHorizontal - è confuso – AlexeyVMP

24

aggiornato per Swift 3

Centro nel container

enter image description here

Il codice di seguito fa la stessa cosa come il centraggio nella 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 
    // ... 
} 

Metodo 1: Stile Anchor

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

Metodo 2: NSLayoutConstraint Stile

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 

Note

  • Lo stile di ancoraggio è il metodo preferito rispetto allo stile NSLayoutConstraint, tuttavia è disponibile solo da iOS 9, quindi se stai supportando iOS 8, devi comunque utilizzare lo stile NSLayoutConstraint.
  • Sarà inoltre necessario aggiungere i vincoli di lunghezza e larghezza.
  • La mia risposta completa è here.
1

Se non si cura di questo problema essendo specificamente circa un Tableview, e vi piacerebbe solo centrare un punto di vista in cima ad un'altra vista qui è di farlo:

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) 
5

L'ObjectiveC equivalente è:

myView.translatesAutoresizingMaskIntoConstraints = NO; 

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

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

migliore per me, Grazie –