ios schermo Come posso riorganizzare le viste quando si esegue la rotazione automatica con l'autolayout?




rotazione schermo samsung (2)

Ora che UIStackView è disponibile in iOS9, una soluzione più semplice e garantita sarebbe quella di aggiungere entrambe le viste a uno stackview, collegare lo stackview a un IBOutlet e quindi aggiungere il seguente codice al viewcontroller:

- (void) adjustViewsForOrientation:(UIInterfaceOrientation) orientation {

if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown || orientation == UIInterfaceOrientationUnknown)
    self.stackView.axis = UILayoutConstraintAxisVertical;
else
    self.stackView.axis = UILayoutConstraintAxisHorizontal;

[self.stackView setNeedsLayout];
[self.stackView setNeedsDisplay];

}

e chiamare questo metodo da

-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

Spesso mi imbatto in questo problema in cui voglio che le mie viste siano disposte in un modo per il ritratto e in modo alquanto drasticamente differente per il paesaggio.

Per un esempio semplificato, considerare quanto segue:

Ritratto:

Paesaggio:

Nota come in verticale le immagini sono impilate verticalmente, ma in orizzontale, sono affiancate?

Naturalmente, posso calcolare manualmente le posizioni e le dimensioni, ma per le viste più complicate, questo diventa rapidamente complesso. Inoltre, preferirei utilizzare l'Autolayout, quindi c'è meno codice specifico del dispositivo (se non del tutto). Ma sembra un sacco di codice Autolayout da scrivere. C'è un modo per impostare i vincoli per questo genere di cose attraverso lo storyboard?


Ci sono due funzionalità poco utilizzate del generatore di interfacce di Xcode che possiamo utilizzare qui per rendere esattamente questo tipo di cosa una sincronizzazione.

  1. È possibile creare connessioni NSLayoutConstraints per NSLayoutConstraints .
  2. È possibile collegare "collezioni outlet", che è una matrice di oggetti IBOutlet .

Quindi, tenendo presente questi due aspetti, l'essenza di ciò che vogliamo fare è creare tutti i nostri vincoli di autolayout per un unico orientamento, collegandoli tutti in una raccolta di prese. Ora, per ciascuno di questi vincoli, deselezionare l'opzione "Installato" sul generatore di interfacce. Quindi realizza tutte le nostre collezioni di outlet per un altro layout e collegale ad un'altra collezione di negozi. Possiamo creare tanti di questi gruppi di layout come vogliamo.

È importante notare che avremo bisogno di un riferimento a qualsiasi elemento dell'interfaccia utente che abbia dei vincoli installati direttamente, e avremo bisogno di una raccolta separata non solo per ogni layout che vogliamo, ma per ogni oggetto UI che ha vincoli installati direttamente su di esso .

Diamo un'occhiata all'esempio abbastanza semplificato della tua domanda.

Se si guarda nell'elenco dei vincoli a sinistra, è possibile vedere la metà di essi in grigio. I vincoli in grigio sono i vincoli del paesaggio. Ho creato tutto questo, quindi deselezionato "Installato" per ognuno di essi:

Nel frattempo, i vincoli di tipo normale e senza grinze sono i vincoli del ritratto. Per questi, li ho lasciati "Installato". Non è assolutamente necessario lasciare nessuno di essi installato, ma si verificheranno dei problemi se si lasciano più serie installate (probabilmente sono in conflitto).

Assicurati di non selezionare "Rimuovi in ​​fase di costruzione" per uno di questi. Non vogliamo che i vincoli "rimossi" al momento della compilazione. Ciò significa semplicemente che il vincolo non è stato creato affatto (quindi perderemo il riferimento ad esso). Se lasciamo questo segno segnato mentre abbiamo un IBOutlet al vincolo, Xcode genererà un avvertimento:

Configurazione non supportata
Connessione al vincolo del segnaposto. I vincoli contrassegnati come segnaposti in IB non dovrebbero avere alcuna connessione poiché questi vincoli non sono compilati nel documento e non esisteranno in fase di runtime.

Ad ogni modo, ora abbiamo bisogno di collegare i vincoli a una presa in modo che possiamo accedervi in ​​fase di esecuzione.

Tenere premuto Ctrl e fare clic e trascinare da uno dei vincoli al file del codice sorgente, proprio come si collegherebbe qualsiasi altro elemento dell'interfaccia utente. Nella finestra di dialogo che si apre, scegli Outlet Collection e un nome descrittivo:

Ora collega tutti gli altri vincoli che corrispondono a quel gruppo di vincoli nella stessa collezione di prese:

Una volta che abbiamo finito di collegare tutti i nostri vincoli, è solo questione di rimuoverli / aggiungerli al momento opportuno.

Per un esempio così semplice come lo scenario descritto nella domanda, possiamo sovrascrivere updateViewConstraints con un codice come questo:

veloce

class ViewController: UIViewController {
    @IBOutlet var landscapeConstraints: [NSLayoutConstraint]!
    @IBOutlet var portraitConstraints: [NSLayoutConstraint]!

    override func updateViewConstraints() {
        let isPortrait = self.view.bounds.width < self.view.bounds.height

        self.view.removeConstraints(self.portraitConstraints)
        self.view.removeConstraints(self.landscapeConstraints)
        self.view.addConstraints(isPortrait ? self.portraitConstraints : self.landscapeConstraints)

        super.updateViewConstraints()
    }
}

Objective-C

@interface ViewController()

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints;

@end

@implementation ViewController

- (void)updateViewConstraints {
    BOOL isPortrait = self.view.bounds.size.width < self.view.boudns.size.height;

    [self.view removeConstraints:self.portraitConstraints];
    [self.view removeConstraints:self.landscapeConstraints];
    [self.view addConstraints:(isPortrait ? self.portraitConstraints : self.landscapeConstraints)];

    [super updateViewConstraints];
}

@end

Non stiamo controllando quale serie di vincoli la vista aveva in precedenza, quindi rimuoviamo entrambi i nostri set di vincoli e quindi aggiungiamo il set appropriato che vogliamo usare.

Questo è tutto il codice che dobbiamo gestire per modificare completamente un'intera serie di vincoli su un oggetto in fase di esecuzione. Ciò consente di lavorare nel builder dell'interfaccia per impostare tutti i nostri vincoli invece di dover farlo a livello di codice (che trovo un po 'più noioso e soggetto a errori).

Il risultato finale? Riarrangiamento di autorotazione dall'aspetto molto piacevole senza tirare fuori i capelli facendo il codice di autolayout fatto perfettamente:





xcode-storyboard