2012-12-06 2 views
44

Desidero modificare i vincoli di layout quando il dispositivo ruota. Il mio UIViewController è composto da 2 UIViews, in orizzontale sono allineati orizzontalmente, e in verticale sono allineati verticalmente.iOS modifica i vincoli di layout automatico quando il dispositivo ruota

funziona in realtà, in willAnimateRotationToInterfaceOrientation, io rimuovere i vincoli desiderati e li ha sostituiti con altri per avere il layout di destra ...

Ma ci sono problemi, durante il layout rotazione automatica inizia a rompere i vincoli prima willAnimateRotationToInterfaceOrientation si chiama , quindi dove intendiamo sostituire i nostri vincoli quando si verifica il riorientamento del dispositivo?

Un altro problema è la prestazione, dopo un paio di giri il sistema non rompere più vincoli, ma ho un enorme calo di prestazioni, soprattutto in modalità ritratto ...

+0

per favore aggiungi qui il tuo codice –

+0

@Makleesh: sì hai ragione, un sacco di problemi emergono quando si utilizza il layout automatico, ma li trovo abbastanza utile .. comunque, sembra che sarà il nuovo modo di fare le cose, meglio ottenere dentro adesso piuttosto tardi. – vitaminwater

+0

@Waseem: Non ho davvero il codice da pubblicare ... come ho detto i vincoli sono stati infranti prima ancora che il mio codice sia eseguito, quindi non so davvero quale codice potrei pubblicare! – vitaminwater

risposta

49

In willRotateToInterfaceOrientation:duration:, inviare setNeedsUpdateConstraints a qualsiasi vista che necessita dei suoi vincoli modificati.

In alternativa, creare una sottoclasse UIView. Nella sottoclasse, registrati per ricevere UIApplicationWillChangeStatusBarOrientationNotification.Quando ricevi la notifica, invia te stesso setNeedsUpdateConstraints.

Imposta il flag needsUpdateConstraints sulla vista. Prima che il sistema esegua il layout (inviando i messaggi layoutSubviews), invia un messaggio updateConstraints a qualsiasi vista con il flag needsUpdateConstraints impostato. Questo è dove devi modificare i tuoi vincoli. Crea una sottoclasse UIView e sostituisci updateConstraints per aggiornare i tuoi vincoli.

+0

Questo è molto bello e funziona perfettamente. Nella mia implementazione sto iterando su [visualizza i vincoli] e rimuovendo ciascuno prima di aggiungere i vincoli specifici dell'orientamento. Questo è uno scambio all'ingrosso e il cambiamento animato sembra fantastico. –

+2

Devi sottoclasse ogni vista che avrà i suoi vincoli modificati, o puoi farlo in qualche modo completamente dal controller della vista? Sembra che una situazione molto, molto comune sarebbe quella di modificare alcune larghezze e altezze per i cambiamenti di rotazione, ma sarebbe piuttosto brutto se si dovesse compilare il layout con più classi personalizzate per molte viste interne. – Tenfour04

+1

È possibile creare una classe personalizzata per la vista di livello superiore e assegnarla a tutte le sottoview che richiedono vincoli modificati. Quindi è possibile impostare tutti i vincoli nel metodo 'updateConstraints' della classe personalizzata. –

2

esclusione -(void) viewWillLayoutSubviews nel vostro UIViewController per aggiornare i vostri vincoli come sotto codice:

-(void) viewWillLayoutSubviews { 
    switch(self.interfaceorientation) 
    { 
      case UIInterfaceOrientationLandscapeLeft: 

       break; 
      case UIInterfaceOrientationLandscapeRight: 

       break; 

      case UIDeviceOrientationPortrait: 

       break; 

      case UIDeviceOrientationPortraitUpsideDown: 

       break; 

    } 
} 
+0

layoutSubviews è un metodo UIView, non è sicuro che sia la strada da percorrere, ma grazie! Questo progetto è stato spedito ora, quindi non posso davvero testarlo comunque, l'approccio più vicino a quello che stai proponendo sarebbe usare viewWillLayoutSubviews da UIViewController, penso di averlo provato senza successo .. – vitaminwater

+2

Primo, devi usare '[super layoutSubviews]' se stai usando l'autolayout. In secondo luogo, non si desidera modificare i vincoli in 'layoutSubviews', perché' layoutSubviews' viene inviato ** dopo ** il sistema ha risolto i vincoli. Cambiando i vincoli qui verrà attivato un altro passaggio di layout (per risolvere i nuovi vincoli) al prossimo turno del ciclo di esecuzione. –

+0

Sembra che il metodo corretto per implementare/eseguire l'override qui sia 'viewWillLayoutSubviews'. –

13

C'è una spiegazione molto buona del layout automatico e delle rotazioni nel post di Matthijs Hollemans. Puoi trovarlo qui: http://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2

In genere, sono necessari circa 4 vincoli per posizionare correttamente la vista. Se le mie visualizzazioni hanno dimensioni costanti, preferisco pin altezza e larghezza. Dopodiché puoi utilizzare i vincoli Leading e Top space per fare quello che vuoi. Ad esempio, è possibile impostare IBOutlets per leader e vincoli di spazio top per i vostri punti di vista:

@interface ViewController : UIViewController { 
    IBOutlet NSLayoutConstraint *_leadingSpaceConstraint; 
    IBOutlet NSLayoutConstraint *_topSpaceConstraint; 
} 

allora il controllo trascinare dalla presa al vincolo. Ora è possibile modificare direttamente la visualizzazione vincolo dal codice:

_leadingSpaceConstraint.constant = NEW_CONSTRAINT_VALUE; 

per applicare le modifiche è necessario chiamare:

[self.view layoutIfNeeded]; 

E se si vuole farlo animato:

[UIView animateWithDuration:0.25 
       animations:^{ 
        [self.view layoutIfNeeded]; 
       }]; 

Penso che funzionerà in willAnimateRotationToInterfaceOrientation, perché non è necessario interrompere alcun vincolo con questo approccio.

Alcuni esempi: Si dispone di due viste quadrate in orientamento verticale, una sotto l'altra. Ad esempio, imposta i vincoli "spazio principale per superview" a 20. Quindi imposta "top space to superview constraint" a 20 per la prima vista e a 120 per la seconda. Sarà la nostra impostazione predefinita.

Quindi, dopo la rotazione è necessario ricalcolare i vincoli. Ora imposta entrambi i vincoli principali su 20 e i vincoli principali su 20 e 120 rispettivamente. Quindi effettua il commit delle modifiche con layoutIfNeeded.

Spero che possa essere d'aiuto.

+0

Mi sembra che tu stia sconfiggendo lo scopo dell'autolayout lì, se imposti una larghezza e un'altezza fisse, e aggiungi lo spazio superiore/sinistro per il posizionamento, non fai altro che molla e montanti. ovviamente non ci sono vincoli di borken in questo modo poiché non si aggiungono vincoli che collegano le viste insieme; ad esempio, se devi gestire più di una dimensione/rapporto dello schermo, dovrai creare casi speciali, che è quello che tende ad evitare l'autolayout! – vitaminwater

+0

Penso che sia solo il caso speciale. Hai bisogno di dimensioni fisse e posizione dinamica - puoi ottenerlo. Hai bisogno di dimensioni dinamiche - puoi farlo anche tu. L'Autolayout ti consente di implementare le dinamiche quando e dove vuoi. Molla e montanti - non. – Flar

+0

Ci sono alcuni casi speciali in cui è necessario mescolare alcune dimensioni hard-coded che reagiscono alle rotazioni. Ad esempio, in una vista di scorrimento che ha attivato il paging, in cui si desidera che le viste interne abbiano la stessa larghezza dello schermo in modo che ciascuna si allinea con lo schermo quando si effettua il paging. Non vale la pena disattivare l'autolayout fintanto che c'è una soluzione come questa. L'Autolayout è un enorme risparmio di tempo per supportare tutte le diverse risoluzioni del dispositivo ed è probabile che i futuri dispositivi aggiungano ancora più risoluzioni da supportare. – Tenfour04

Problemi correlati