Creazione di vincoli di layout a livello di codice


84

So che molte persone hanno già fatto tonnellate di domande su questo, ma anche con le risposte non riesco a farlo funzionare.

Quando ho a che fare con i vincoli sullo storyboard, è facile ma nel codice ho difficoltà. Cerco, ad esempio, di avere una visuale che stia sul lato destro e abbia l'altezza dello schermo in base all'orientamento dello schermo. Questo è il mio codice:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Non soddisfa alcuni vincoli. Non vedo cosa c'è che non va. Inoltre, perché non posso usare una proprietà like self.myViewinvece di una variabile locale come myView?


Cos'è vivi nel codice sopra?
iDev

14
Modificare il titolo in "iOS" invece di "IOS" - Quest'ultimo si riferisce al sistema operativo switch / router di Cisco. Mi ha confuso. Grazie.
armani

1
Diverse domande su questo: (1) quale errore ricevi quando "non soddisfa alcuni vincoli"? (2) Stai traducendo il ridimensionamento automatico in vincoli su myView? (3) Cos'è vivi(come ha chiesto ACB)? (4) Hai una proprietà myViewdichiarata self?
Tim

1
ih Tim, beh scusa il vivi, ho toccato troppo velocemente ... è myView. Cosa intendi per tradurre? Tutto quello che faccio è sul codice sopra. Riguardo alla proprietà, ho altre viste che sono dichiarate come proprietà ma quando implemento lo stesso codice a quelle proprietà si blocca ... il messaggio "errore" è davvero grande, non posso incollarlo qui
pierre23

Per rimuovere temporaneamente i vincoli da una vista particolare, eseguire questa operazione stackoverflow.com/questions/13388104/…
Sam B

Risposte:


106

Quando si utilizza Layout automatico nel codice, l'impostazione della cornice non ha effetto. Quindi il fatto che tu abbia specificato una larghezza di 200 nella vista sopra, non significa nulla quando imposti dei vincoli su di essa. Affinché un set di vincoli di visualizzazione sia univoco, ha bisogno di quattro cose: una posizione x, una posizione y, una larghezza e un'altezza per ogni stato dato.

Attualmente nel codice sopra, ne hai solo due (altezza, relativa alla superview e posizione y, rispetto alla superview). Oltre a questo, hai due vincoli obbligatori che potrebbero entrare in conflitto a seconda di come sono impostati i vincoli della superview della vista. Se la superview dovesse avere un vincolo obbligatorio che specifica che l'altezza deve essere un valore inferiore a 748, si otterrà un'eccezione "vincoli insoddisfacenti".

Il fatto che tu abbia impostato la larghezza della vista prima di impostare i vincoli non significa nulla. Non terrà nemmeno in considerazione il vecchio frame e calcolerà un nuovo frame in base a tutti i vincoli che ha specificato per quelle viste. Quando si ha a che fare con il layout automatico nel codice, in genere creo solo una nuova vista usando initWithFrame:CGRectZeroo semplicemente init.

Per creare il set di vincoli richiesto per il layout che hai descritto verbalmente nella tua domanda, dovresti aggiungere alcuni vincoli orizzontali per delimitare la larghezza e la posizione x in modo da fornire un layout completamente specificato:

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

La descrizione verbale di questo layout si legge come segue a partire dal vincolo verticale:

myView riempirà l'altezza della sua superview con un'imbottitura superiore e inferiore uguale allo spazio standard. La superview di myView ha un'altezza minima di 748 punti. La larghezza di myView è di 200 punti e ha un riempimento destro uguale allo spazio standard rispetto alla sua superview.

Se desideri semplicemente che la vista riempia l'intera altezza della superview senza vincolare l'altezza della superview, ometti semplicemente il (>=748)parametro nel testo in formato visivo. Se pensi che il (>=748)parametro sia necessario per dargli un'altezza - in questo caso non lo fai: fissando la vista ai bordi della superview usando la sintassi barra ( |) o barra con spazio ( |-, -|), stai dando alla tua vista una y -posizione (bloccando la vista su un bordo singolo) e una posizione y con altezza (bloccando la vista su entrambi i bordi), soddisfacendo così il vincolo impostato per la vista.

Riguardo alla tua seconda domanda:

Usando NSDictionaryOfVariableBindings(self.myView)(se avevi una configurazione di proprietà per myView) e inserendola nel tuo VFL da usareself.myView nel tuo testo VFL, probabilmente otterrai un'eccezione quando il layout automatico tenta di analizzare il tuo testo VFL. Ha a che fare con la notazione del punto nelle chiavi del dizionario e il sistema che cerca di utilizzare valueForKeyPath:. Vedi qui per una domanda e una risposta simili .


Non dimenticare che alcuni oggetti come UILabel hanno una dimensione intrinseca e non devi impostare la larghezza o l'altezza di quell'oggetto, solo la sua posizione. Tuttavia, se imposti l'altezza o la larghezza, credo che rimuova entrambi e quindi devi fornire entrambi.
Nick Turner

Anche se questa risposta non ha risposto alla mia domanda, mi ha aiutato a realizzare qualcosa. Grazie per esserci! :)
Matej

1
Finora l'unica introduzione al layout automatico concisa e leggibile su Internet.
Joey Carson

plz help me la mia domanda è questa ... io non so come usare i vincoli di programmazione stackoverflow.com/questions/36326288/...

61

Ciao, ho usato molto questa pagina per i vincoli e per "come fare". Mi ci è voluta un'eternità per arrivare al punto di realizzare che avevo bisogno di:

myView.translatesAutoresizingMaskIntoConstraints = NO;

per far funzionare questo esempio. Grazie Userxxx, Rob M. e soprattutto larsacus per la spiegazione e il codice qui, è stato inestimabile.

Ecco il codice completo per eseguire gli esempi precedenti:

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

11

Versione rapida

Aggiornato per Swift 3

Questo esempio mostrerà due metodi per aggiungere a livello di codice i seguenti vincoli come se lo si facesse in Interface Builder:

Larghezza e altezza

inserisci qui la descrizione dell'immagine

Centro nel contenitore

inserisci qui la descrizione dell'immagine

Codice Boilerplate

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

Metodo 1: stile di ancoraggio

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Metodo 2: NSLayoutConstraint Style

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

Appunti

  • Lo stile di ancoraggio è il metodo preferito rispetto allo NSLayoutConstraintstile, tuttavia è disponibile solo da iOS 9, quindi se stai supportando iOS 8, dovresti comunque usare lo NSLayoutConstraintstile.
  • Vedere anche la documentazione sulla creazione di vincoli a livello di codice .
  • Vedi questa risposta per un esempio simile di aggiunta di un vincolo di blocco.

5

Per quanto riguarda la tua seconda domanda sulle proprietà, puoi usare self.myViewsolo se l'hai dichiarata come proprietà in classe. Poiché myViewè una variabile locale, non puoi usarla in questo modo. Per maggiori dettagli su questo, ti consiglio di consultare la documentazione di Apple sulle proprietà dichiarate ,


5

perché non posso usare una proprietà come self.myViewinvece di una variabile locale come myView?

prova a usare:

NSDictionaryOfVariableBindings(_view)

invece di self.view


Questo fa sì che la mia app si blocchi, dà il messaggio: "Impossibile analizzare il formato del vincolo: polylineImageView non è una chiave nel dizionario delle viste".
Tai Le

4

Tieni inoltre presente che da iOS9 possiamo definire vincoli in modo programmatico "più conciso e più facile da leggere" utilizzando le sottoclassi della nuova classe helper NSLayoutAnchor .

Un esempio dal documento:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.