Sto provando a comprendere i limiti di autolayout. A seguito di una sfida guida Ray W (senza una soluzione e di discussione), il layout dovrebbe assomiglia a questo:Vincoli nel codice utilizzando swift - impossibile attivare
Farlo in IB stato abbastanza facile - creare una vista di colore giallo con una larghezza e altezza, centrato verticalmente e appuntato orizzontalmente ai margini; quindi crea etichette, campi e un pulsante con semplici vincoli all'interno di quella vista.
La mia prima domanda è: se le etichette hanno una dimensione intrinseca del contenuto e tutto il resto è fissato alla vista gialla, allora perché devo definire una larghezza e un'altezza fissa? Perché non inferire la larghezza e l'altezza dal contenuto intrinseco delle sue sottoview?
Passando e cercando di ricreare questo layout in codice mi stava dando un errore:
Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with items
<UILabel: 0x7a961d60; frame = (0 0; 0 0); text = 'Password:'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7a961e40>>
and<UIView: 0x7a96b6f0; frame = (0 0; 0 0); layer = <CALayer: 0x7a96b880>>
because they have no common ancestor. Does the constraint reference items in different view hierarchies? That's illegal.'
Seconda domanda: quali sono questi livelli, e tutti i miei punti di vista sono in una heirachy - superview contiene la vista di colore giallo contiene le etichette e i campi di testo.
Dopo molto dolore, ho provato a ricreare esattamente i vincoli apportati in IB, ma questo ha aggiunto solo il seguente errore: Impossibile soddisfare contemporaneamente i vincoli.
(
"<NSLayoutConstraint:0x7ac57370 H:[UIView:0x7a96b6f0(0)]>",
"<NSLayoutConstraint:0x7ac57400 H:|-(8)-[UILabel:0x7a96bb50'Username:'] (Names: '|':UIView:0x7a96b6f0)>",
"<NSLayoutConstraint:0x7ac57430 UILabel:0x7a96bb50'Username:'.trailing == UITextField:0x7a961020.leading + 8>",
"<NSLayoutConstraint:0x7ac57520 UITextField:0x7a961020.trailing == UIView:0x7a96b6f0.trailing - 8>")
Domanda/e finale/e: come faccio a sapere quale vista è vista 0x7aetc? E dov'è questo vincolo nel mio codice? Il resto sembra ok (?).
Devo fare qualcosa di molto sbagliato ad un livello base.
Ecco il mio codice:
import UIKit
class ViewController: UIViewController {
let centerView = UIView()
let usernameLabel = UILabel()
let passwordLabel = UILabel()
let usernameField = UITextField()
let passwordField = UITextField()
let submitButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
centerView.backgroundColor = UIColor.yellowColor()
usernameLabel.text = "Username:"
passwordLabel.text = "Password:"
usernameField.borderStyle = .RoundedRect
passwordField.borderStyle = .RoundedRect
submitButton.setTitle("Submit!", forState: .Normal)
submitButton.setTitleColor(UIColor.blackColor(), forState: .Normal)
submitButton.setTitleColor(UIColor.blueColor(), forState: .Highlighted)
view.addSubview(centerView)
self.centerView.addSubview(usernameField)
self.centerView.addSubview(passwordField)
self.centerView.addSubview(usernameLabel)
self.centerView.addSubview(submitButton)
let constraintCenterViewHeight = NSLayoutConstraint(item: centerView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0)
let constraintCenterViewWidth = NSLayoutConstraint(item: centerView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0)
let constraintCenterViewCenterX = NSLayoutConstraint(item: centerView, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1.0, constant: 0)
let constraintCenterViewCenterY = NSLayoutConstraint(item: centerView, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1.0, constant: 0)
let constraintUsernameLabelHLeading = NSLayoutConstraint(item: usernameLabel, attribute: .Leading, relatedBy: .Equal, toItem: centerView, attribute: .Leading, multiplier: 1.0, constant: 8)
let constraintUsernameLabelHTrailing = NSLayoutConstraint(item: usernameLabel, attribute: .Trailing, relatedBy: .Equal, toItem: usernameField, attribute: .Leading, multiplier: 1.0, constant: 8)
let constraintUsernameLabelAlignBottom = NSLayoutConstraint(item: usernameLabel, attribute: .Bottom, relatedBy: .Equal, toItem: usernameField, attribute: .Bottom, multiplier: 1.0, constant: 0)
let constraintUsernameFieldVTop = NSLayoutConstraint(item: usernameField, attribute: .Top, relatedBy: .Equal, toItem: centerView, attribute: .Top, multiplier: 1.0, constant: 8)
let constraintUsernameFieldHTrailing = NSLayoutConstraint(item: usernameField, attribute: .Trailing, relatedBy: .Equal, toItem: centerView, attribute: .Trailing, multiplier: 1.0, constant: -8)
let constraintUsernameFieldVBottom = NSLayoutConstraint(item: usernameField, attribute: .Bottom, relatedBy: .Equal, toItem: passwordField, attribute: .Top, multiplier: 1.0, constant: 8)
let constraintPasswordLabelHLeading = NSLayoutConstraint(item: passwordLabel, attribute: .Leading, relatedBy: .Equal, toItem: centerView, attribute: .Leading, multiplier: 1.0, constant: 8)
let constraintPasswordLabelHTrailing = NSLayoutConstraint(item: passwordLabel, attribute: .Trailing, relatedBy: .Equal, toItem: passwordField, attribute: .Leading, multiplier: 1.0, constant: 8)
let constraintPasswordLabelAlignBottom = NSLayoutConstraint(item: passwordLabel, attribute: .Bottom, relatedBy: .Equal, toItem: passwordField, attribute: .Bottom, multiplier: 1.0, constant: 0)
let constraintPasswordFieldHTrailing = NSLayoutConstraint(item: passwordField, attribute: .Trailing, relatedBy: .Equal, toItem: centerView, attribute: .Trailing, multiplier: 1.0, constant: -8)
centerView.setTranslatesAutoresizingMaskIntoConstraints(false)
usernameLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
usernameField.setTranslatesAutoresizingMaskIntoConstraints(false)
passwordField.setTranslatesAutoresizingMaskIntoConstraints(false)
passwordLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
// submitButton.setTranslatesAutoresizingMaskIntoConstraints(false)
NSLayoutConstraint.activateConstraints([constraintCenterViewHeight, constraintCenterViewWidth, constraintCenterViewCenterX, constraintCenterViewCenterY, constraintUsernameLabelHLeading,
constraintUsernameLabelHTrailing, constraintUsernameLabelAlignBottom, constraintUsernameFieldVTop, constraintUsernameFieldHTrailing, constraintUsernameFieldVBottom, constraintPasswordLabelHLeading, constraintPasswordLabelHTrailing, constraintPasswordLabelAlignBottom, constraintPasswordFieldHTrailing])
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Ho guardato questo codice per giorni e non ho mai visto la sottoview mancante, né la larghezza e l'altezza come 0! Ah-ha, (mentre stavo scrivendo che non l'ho capito) il mio vecchio cervello sordo pensava che il bordo finale del nome utenteLabel al nome utente Il bordo anteriore del campo dovesse essere 8 punti più lungo lungo l'asse Y o orizzontale. MA questo è solo un altro stupido errore. Voglio che il bordo finale del nome utenteLabel al nome utente Il bordo anteriore del campo 8 punti indietro lungo la Y o l'asse orizzontale. Molto dispiaciuto, e molto grato per il fatto che tu l'abbia indicato. È bello sapere che questa roba funziona se la capisci. – DrWhat