Posso disabilitare il layout automatico per una sottoview specifica in fase di esecuzione?


104

Ho una vista che deve avere la sua cornice manipolata a livello di codice: è una sorta di vista del documento che si avvolge al suo contenuto che viene quindi fatto scorrere e ingrandito attorno a una superview manipolando l'origine del frame. Il layout automatico combatte con questo in fase di esecuzione.

Disabilitare completamente il layout automatico sembra un po 'difficile perché potrebbe essere ragionevolmente usato per gestire il layout per le altre viste. Sembra che quello che potrei desiderare è una sorta di "vincolo nullo".

Risposte:


168

Ho avuto lo stesso problema. Ma l'ho risolto.
Sì, puoi disabilitare il layout automatico in fase di esecuzione per uno specifico UIView, invece di disabilitarlo per l'intero xib o storyboard che è impostato per impostazione predefinita in Xcode 4.3 e versioni successive.

Imposta translatesAutoresizingMaskIntoConstraintssu YES, prima di impostare la cornice della tua sottoview:

self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);

2
Questo sembra eccessivo per alcuni casi più complicati con molte visualizzazioni. Per qualcosa di semplice come questo, va bene.
esh

@ MuhammadAamirALi rimuovere la sottoview e quindi aggiungerla di nuovo potrebbe ridurre le prestazioni. Possiamo archiviare una soluzione migliore?
Nhat Dinh

2
@DinhNhat ho chiarito la risposta. Non è necessario rimuovere e riaggiungere la sottoview.
Leandros

5
Viene visualizzato l'avviso: "Impossibile soddisfare i vincoli contemporaneamente".
NSPratik

1
Mi hai salvato la giornata ... traduceAutoresizingMaskIntoConstraints
Tintenklecks

50

Ho avuto un problema simile in cui Autolayout sovrascriveva alcune delle mie impostazioni di frame in fase di esecuzione (avevo una visualizzazione dinamica che in alcuni casi spingeva un nuovo controller di visualizzazione ... premendo e quindi premendo Indietro si ripristinava la visualizzazione iniziale).

Ho aggirato questo problema inserendo il mio codice di manipolazione nel viewDidLayoutSubviewsmio controller di visualizzazione. Questo sembra essere chiamato dopo qualsiasi vincolo che mojo viene chiamato, ma prima di viewDidAppear, quindi l'utente non è più saggio.


1
Non funziona per self.navigationItem.titleView. Ancora non rispetta il cambio di telaio.
Henrik Erlandsson

1
Se stai provando a muck con il frame di una vista del titolo, lo metterei all'interno di una vista del contenitore e aggiungerei la vista del contenitore come vista personalizzata del navigationItem.
jmstone617

2
Questo ha funzionato anche per me. Avevo sprecato 2h: 22m sbattendo la testa contro il proverbiale muro prima di scoprire questa soluzione alternativa.
TMc

Grazie uomo. Sono nel mio secondo giorno alle prese con questo problema e ora funziona!
apostolov

28

Forse solo impostando translatesAutoresizingMaskIntoConstraintssu YES(e non aggiungendo ulteriori vincoli che influenzano quella vista) potrai impostare il frame senza combattere il sistema di layout automatico.


17

In iOS 8 puoi impostare un NSLayoutConstraint in modo che sia attivo o meno. Quindi, se sto usando il generatore di interfacce, aggiungo tutti i miei vincoli a un OutletCollection e quindi attivo o disattivo usando:

NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)

La particolare applicazione per cui lo sto usando qui ha diversi vincoli in modalità verticale e orizzontale e si attiva / disattiva in base alla rotazione del dispositivo. Significa che posso creare alcune modifiche al layout complesse tutte in Interface Builder per entrambi gli orientamenti, e utilizzare comunque il layout automatico senza il dettagliato codice di layout automatico.

Oppure puoi attivare / disattivare utilizzando removeConstraints e addConstraints.


Ci scusiamo per aver dirottato una domanda così vecchia, ma posso chiederti come sei riuscito ad aggiungere vincoli di layout per layout diversi in primo luogo? Non riesco a trovare un'opzione all'interno del generatore di interfacce per abilitare / disabilitare i vincoli. O hai semplicemente aggiunto vincoli per entrambi i layout e hai semplicemente ignorato il generatore di interfacce che si lamentava di vincoli non validi (sovrascrittivi)?
Malte

Bene, potresti farlo usando le classi di dimensioni: developer.apple.com/library/ios/recipes/… , ma non potevo farlo in questo modo perché supportavo anche iOS 7 e le classi di dimensioni non supportano completamente iOS 7 L'ho fatto abbassando la priorità del vincolo in conflitto. Non è l'ideale, ma impedisce l'avviso. Penso che sia così che ho fatto comunque ...
bandejapaisa

9

Non so se questo aiuterà qualcun altro, ma ho scritto una categoria per renderlo conveniente perché mi ritrovo a farlo molto.

UIView + DisableAutolayoutTemporarily.h

#import <UIKit/UIKit.h>

@interface UIView (DisableAutolayoutTemporarily)

// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;

@end

UIView + DisableAutolayoutTemporarily.m

#import "UIView+DisableAutoResizeTemporarily.h"
@implementation UIView (DisableAutoResizeTemporarily)

- (void)resizeWithBlock:(void (^)(UIView * view))block
{
    UIView *superview = self.superview;
    [self removeFromSuperview];
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    __weak UIView *weakSelf = self;
    block(weakSelf);
    [superview addSubview:self];
}

@end

Lo uso in questo modo:

[cell.argumentLabel resizeWithBlock:^(UIView *view) {
    [view setFrame:frame];
}];

Spero che sia d'aiuto.


Geniale! Ho usato una versione modificata del tuo codice per scrivere una semplice funzione "hideControl" per qualsiasi UIView. Fondamentalmente imposta l'altezza di una UIView su 0, ma, soprattutto, utilizza il tuo codice per fare in modo che AutoLayout lo gestisca correttamente (a differenza dell'utilizzo di "someView.hidden = TRUE"). Quindi i controlli che apparivano sotto il controllo nascosto e avevano una spaziatura verticale ad esso collegata, ora si spostavano verso l'alto sullo schermo per riempire il vuoto, dove prima appariva la vista nascosta.
Mike Gledhill

6

È possibile impostare il translatesAutoresizingMaskIntoConstraintstipo Boolean, Valore Sì negli attributi di runtime definiti dall'utente di UIView che si desidera in xib / storyboard.


2
  • Apri progetto in 4.5
  • Seleziona storyboard
  • Apri l'ispettore file
  • In Interface Builder Document deseleziona "Usa layout automatico"

Puoi dividere su più storyboard se desideri utilizzare il layout automatico per alcune visualizzazioni.


10
Ciò disabilita il layout automatico per l'intero storyboard / pennino. Quello che stavo cercando era un modo (idealmente programmatico) per avere particolari visualizzazioni secondarie all'interno di uno storyboard / pennino non utilizzare il layout automatico lasciando il resto a fare qualunque cosa lo storyboard / pennino specificato.
terriblememory

È possibile utilizzare più storyboard e richiamare semplicemente quelli con / senza layout automatico secondo necessità: // Inizializza il controller della visualizzazione dei dettagli e della memoria per visualizzare UIStoryboard * sb = [UIStoryboard storyboardWithName: @ "Storyboard" bundle: [NSBundle mainBundle]]; DetailViewController * dvController = [sb instantiateViewControllerWithIdentifier: entry.viewName];
Mike Bobbitt

1

Per me ha funzionato per creare la sottoview a livello di programmazione, nel mio caso il layout automatico stava scherzando con una vista che dovevo ruotare attorno al suo centro, ma una volta creata questa vista a livello di programmazione ha funzionato.


1

A mio avviso avevo un'etichetta e un testo. L'etichetta aveva il gesto della padella. L'etichetta si muove bene durante il trascinamento. Ma quando utilizzo la tastiera della casella di testo, l'etichetta ripristina la sua posizione nella posizione originale definita nel layout automatico. Il problema è stato risolto quando ho aggiunto quanto segue rapidamente per l'etichetta. L'ho aggiunto in viewWillAppear ma può essere aggiunto praticamente ovunque tu abbia accesso al campo di destinazione.

self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true

0

Questo è successo a me in un progetto senza storyboard o file xib. Tutto il codice al 100%. Avevo un banner pubblicitario in fondo e volevo che i limiti di visualizzazione si fermassero al banner pubblicitario. La vista si ridimensionerebbe automaticamente dopo il caricamento. Ho provato tutte le risoluzioni su questa pagina ma nessuna ha funzionato.

Ho finito per creare una vista secondaria con l'altezza ridotta e l'ho inserita nella vista principale del controller. Quindi tutto il mio contenuto è andato nella visualizzazione secondaria. Ciò ha risolto il problema molto facilmente senza fare nulla che sembrava andare contro il grano.

Sto pensando che se vuoi una vista che non è la dimensione normale che riempie la finestra, dovresti usare una vista secondaria per quello.


0

Mi sono imbattuto in uno scenario simile, in cui mi sono unito a un progetto avviato con il layout automatico, ma avevo bisogno di apportare modifiche dinamiche a diverse visualizzazioni. Ecco cosa ha funzionato per me:

  1. NON avere viste o componenti disposti in Interface Builder.

  2. Aggiungi le tue visualizzazioni in modo puramente programmatico iniziando con alloc / init e impostando i loro frame in modo appropriato.

  3. Fatto.


0

Invece di disabilitare il layout automatico, calcolerei semplicemente il nuovo vincolo con il frame che stai sostituendo. Mi sembra che sia il modo appropriato. Se si regolano componenti che si basano su vincoli, regolarli di conseguenza.

Ad esempio, se hai un vincolo verticale di 0 tra due viste (myView e otherView) e hai un gesto di panoramica o qualcosa che regola l'altezza di myView, puoi ricalcolare il vincolo con i valori regolati.

self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];

0

Per quelli di voi che utilizzano il layout automatico, consultare la mia soluzione qui . Dovresti fare @IBOutleti vincoli che vuoi regolare e poi cambiare le loro costanti.


-16

se è un file xib:

  1. seleziona il file .xib
  2. seleziona il "Proprietario del file"
  3. mostra le utilità
  4. fare clic su: "File Inspector"
  5. In "Documento Interface Builder" disattiva: "Usa layout automatico"

1
No, questo disabilita il layout automatico per l'intero xib. Quello che stavo cercando è un modo per rimuovere solo una particolare sottoview dal sistema di layout automatico.
terribile
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.