ios8 - Qual è il modo "giusto" per gestire i cambiamenti di orientamento in iOS 8?





orientation uiinterfaceorientation landscape-portrait (5)


Dal punto di vista dell'interfaccia utente, credo che l'utilizzo di Classi di dimensioni sia l'approccio consigliato da Apple per la gestione delle interfacce in diversi orientamenti, dimensioni e dimensioni.

Vedi la sezione: Tratti Descrivi la classe di dimensioni e la scala di un'interfaccia qui: https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html

"iOS 8 aggiunge nuove funzionalità che rendono la gestione delle dimensioni dello schermo e dell'orientamento molto più versatili."

Questo è anche un buon articolo: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

EDIT Link aggiornato: https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (Credit: Koen)

Qualcuno può dirmi l'approccio "giusto" o "migliore" per lavorare con gli orientamenti di interfaccia verticale e orizzontale in iOS 8? Sembra che tutte le funzioni che voglio utilizzare a tale scopo siano deprecate in iOS 8 e la mia ricerca non ha trovato un'alternativa chiara ed elegante. Dovrei davvero guardare la larghezza e l'altezza per determinare da solo se siamo in modalità verticale o orizzontale?

Ad esempio, nel mio controller di visualizzazione, come dovrei implementare il seguente pseudocodice?

if we are rotating from portrait to landscape then
  do portrait things
else if we are rotating from landscape to portrait then
  do landscape things



Apple consiglia di utilizzare le classi di dimensioni come misura approssimativa della quantità di spazio disponibile sullo schermo, in modo che l'interfaccia utente possa modificare in modo significativo il layout e l'aspetto. Considera che un iPad in verticale ha le stesse classi di dimensioni del paesaggio (larghezza regolare, altezza regolare). Ciò significa che l'interfaccia utente dovrebbe essere più o meno simile tra i due orientamenti.

Tuttavia, il passaggio da verticale a orizzontale in un iPad è abbastanza significativo che potrebbe essere necessario apportare alcune modifiche minori all'interfaccia utente, anche se le classi di dimensioni non sono cambiate. Poiché i metodi relativi all'orientamento dell'interfaccia su UIViewController sono stati deprecati, Apple ora consiglia di implementare il seguente nuovo metodo in UIViewController come una sostituzione:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // Code here will execute before the rotation begins.
    // Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Place code here to perform animations during the rotation.
        // You can pass nil or leave this block empty if not necessary.

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Code here will execute after the rotation has finished.
        // Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]

    }];
}

Grande! Ora ricevi le richiamate subito prima dell'avvio della rotazione e al termine. Ma per quanto riguarda effettivamente sapere se la rotazione è di ritratto o di paesaggio?

Apple consiglia di pensare alla rotazione semplicemente come un cambiamento di dimensioni della vista genitore. In altre parole, durante la rotazione dell'iPad da verticale a orizzontale, è possibile considerarla come la visualizzazione a livello di radice modificando semplicemente il suo bounds.size da {768, 1024} a {1024, 768} . Sapendo questo, dovresti usare la size passata in viewWillTransitionToSize:withTransitionCoordinator: metodo sopra per capire se stai ruotando in viewWillTransitionToSize:withTransitionCoordinator: o orizzontale.

Se vuoi un modo ancora più semplice per migrare il codice legacy al nuovo modo di fare iOS 8, considera l'utilizzo di questa semplice categoria su UIView, che può essere utilizzata per determinare se una vista è "portrait" o "landscape" in base alla sua dimensione.

Per ricapitolare:

  1. Dovresti utilizzare le classi di dimensioni per determinare quando mostrare interfacce utente fondamentalmente diverse (ad es. Un'interfaccia utente "simile all'iPhone" e un'interfaccia utente "simile all'iPad")
  2. Se è necessario apportare modifiche minori all'interfaccia utente quando le classi delle dimensioni non cambiano ma le dimensioni del contenitore (visualizzazione padre), ad esempio quando viene ruotato un iPad, utilizzare viewWillTransitionToSize:withTransitionCoordinator: callback in UIViewController.
  3. Ogni vista nella tua app deve prendere decisioni di layout solo in base allo spazio in cui è stato assegnato al layout. Lascia che la gerarchia naturale delle viste copra queste informazioni verso il basso.
  4. Allo stesso modo, non utilizzare lo statusBarOrientation - che è fondamentalmente una proprietà a livello di dispositivo - per determinare se impaginare una vista per "portrait" o "landscape". L'orientamento della barra di stato dovrebbe essere usato solo dal codice che si occupa di cose come UIWindow che effettivamente vivono al livello di root dell'app.



Basato sulla risposta molto ben dettagliata (e accettata) di smileyborg, ecco un adattamento usando swift 3:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        self.collectionView.collectionViewLayout.invalidateLayout()
    })        
}

E nell'implementazione UICollectionViewDelegateFlowLayout ,

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // retrieve the updated bounds
    let itemWidth = collectionView.bounds.width
    let itemHeight = collectionView.bounds.height
    // do whatever you need to do to adapt to the new size
}



Semplicemente uso il Centro di notifica:

Aggiungi una variabile di orientamento (spiegheremo alla fine)

//Above viewdidload
var orientations:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation

Aggiungi notifica quando appare la vista

override func viewDidAppear(animated: Bool) {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name: UIDeviceOrientationDidChangeNotification, object: nil)
}

Rimuovi la notifica quando la vista va via

override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil) 
}

Ottiene l'orientamento corrente quando viene attivata la notifica

func orientationChanged (notification: NSNotification) {
    adjustViewsForOrientation(UIApplication.sharedApplication().statusBarOrientation)
}

Controlla l'orientamento (verticale / orizzontale) e gestisce gli eventi

func adjustViewsForOrientation(orientation: UIInterfaceOrientation) {
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown)
    {
        if(orientation != orientations) {
            println("Portrait")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
    else if (orientation == UIInterfaceOrientation.LandscapeLeft || orientation == UIInterfaceOrientation.LandscapeRight)
    {
       if(orientation != orientations) {
            println("Landscape")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
}

Il motivo per cui aggiungo una variabile di orientamento è perché durante il test su un dispositivo fisico la notifica di orientamento viene chiamata ad ogni minima mossa nel dispositivo, e non solo quando ruota. L'aggiunta delle istruzioni var e if chiama il codice solo se passa all'orientamento opposto.




In Swift dovresti fare la parola chiave is se ti stai interrogando sulla classe corrispondente. Nel filter -closure puoi usare $0 per specificare il primo parametro.

Campione

var (a,b,c,d) = ("String", 42, 10.0, "secondString")
let myArray: Array<Any> = [a,b,c,d]
var onlyStrings = myArray.filter({ return $0 is String })
onlyStrings // ["String", "secondString"]




ios ios8 orientation uiinterfaceorientation landscape-portrait