Was ist der „richtige“ Weg, um mit Orientierungsänderungen in iOS 8 umzugehen?

103

Kann mir bitte jemand den "richtigen" oder "besten" Ansatz für die Arbeit mit Orientierungen der Hoch- und Querformatoberfläche in iOS 8 nennen? Es scheint, dass alle Funktionen, die ich für diesen Zweck verwenden möchte, in iOS 8 veraltet sind, und meine Forschung hat keine klare, elegante Alternative ergeben. Soll ich wirklich die Breite und Höhe betrachten, um selbst festzustellen, ob wir uns im Hoch- oder Querformat befinden?

Wie soll ich beispielsweise in meinem View Controller den folgenden Pseudocode implementieren?

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
rmp251
quelle
3
Lesen Sie die Dokumente für UIViewController. Siehe den Abschnitt mit dem Titel "Umgang mit
Ansichtsrotationen
Dass sie veraltet sind, ist ein Hinweis. Du musst etwas anderes verwenden ... dass etwas anderes AutoLayout und Größenklassen sein sollte :-)
Aaron

Antworten:

260

Apple empfiehlt die Verwendung von Größenklassen als grobes Maß für den verfügbaren Bildschirmbereich, damit Ihre Benutzeroberfläche das Layout und das Erscheinungsbild erheblich ändern kann. Beachten Sie, dass ein iPad im Hochformat dieselben Größenklassen hat wie im Querformat (normale Breite, normale Höhe). Dies bedeutet, dass Ihre Benutzeroberfläche zwischen den beiden Ausrichtungen mehr oder weniger ähnlich sein sollte.

Der Wechsel von Hoch- zu Querformat in einem iPad ist jedoch so bedeutend, dass Sie möglicherweise kleinere Anpassungen an der Benutzeroberfläche vornehmen müssen, obwohl sich die Größenklassen nicht geändert haben. Da die auf die Schnittstellenorientierung bezogenen Methoden UIViewControllerveraltet sind, empfiehlt Apple nun, die folgende neue Methode UIViewControllerals Ersatz zu implementieren :

- (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:]

    }];
}

Toll! Jetzt erhalten Sie Rückrufe, kurz bevor die Rotation beginnt und nachdem sie beendet ist. Aber was ist mit dem tatsächlichen Wissen, ob es sich bei der Rotation um Hoch- oder Querformat handelt?

Apple empfiehlt, Rotation lediglich als Änderung der Größe der übergeordneten Ansicht zu betrachten. Mit anderen Worten, während einer iPad-Rotation von Hoch- zu Querformat können Sie sich das als die Ansicht auf Stammebene vorstellen, die einfach bounds.sizevon {768, 1024}zu wechselt {1024, 768}. Wenn Sie dies wissen, sollten Sie sizedie viewWillTransitionToSize:withTransitionCoordinator:oben beschriebene Methode verwenden, um herauszufinden, ob Sie sich im Hoch- oder Querformat drehen.

Wenn Sie eine noch nahtlosere Methode zum Migrieren von Legacy-Code auf die neue iOS 8-Methode verwenden möchten, sollten Sie diese einfache Kategorie in UIView verwenden, mit der Sie anhand ihrer Funktion bestimmen können, ob eine Ansicht "Hochformat" oder "Querformat" ist Größe.

Um es noch einmal zusammenzufassen:

  1. Sie sollten Größenklassen verwenden, um zu bestimmen, wann grundlegend unterschiedliche Benutzeroberflächen angezeigt werden sollen (z. B. eine "iPhone-ähnliche" Benutzeroberfläche im Vergleich zu einer "iPad-ähnlichen" Benutzeroberfläche).
  2. Wenn Sie kleinere Anpassungen an Ihrer Benutzeroberfläche vornehmen müssen, wenn sich die Größenklassen nicht ändern, die Größe Ihres Containers (übergeordnete Ansicht) jedoch, z. B. wenn sich ein iPad dreht, verwenden Sie den viewWillTransitionToSize:withTransitionCoordinator:Rückruf in UIViewController.
  3. Jede Ansicht in Ihrer App sollte Layoutentscheidungen nur auf der Grundlage des Bereichs treffen, in dem sie für das Layout vorgesehen ist. Lassen Sie die natürliche Hierarchie der Ansichten diese Informationen nach unten kaskadieren.
  4. Verwenden Sie in ähnlicher Weise nicht die statusBarOrientationEigenschaft, die im Grunde genommen eine Eigenschaft auf Geräteebene ist, um zu bestimmen, ob eine Ansicht für "Hochformat" oder "Querformat" angeordnet werden soll. Die Ausrichtung der Statusleiste sollte nur von Code verwendet werden, der sich mit Dingen befasst, UIWindowdie sich tatsächlich auf der Root-Ebene der App befinden.
Smileyborg
quelle
5
Hervorragende Antwort! Übrigens war dein Youtube-Video auf AL unglaublich informativ. Danke fürs Teilen. Hör zu! youtube.com/watch?v=taWaW2GzfCI
smileBot
2
Das einzige Problem, das ich gefunden habe, ist, dass Sie manchmal die Geräteorientierung wissen möchten, und dies lässt Sie es nicht wissen. Auf dem iPad wird es aufgerufen, bevor sich der Statusleisten- oder Geräteorientierungswert ändert. Sie können nicht feststellen, ob der Benutzer das Gerät im Hoch- oder Hochformat hält. Es ist auch unmöglich zu testen, da Spott UIViewControllerTransitionCoordinatorein Albtraum ist :-(
Darrarski
@Darrarski Haben Sie eine elegante Lösung gefunden, um diese Probleme zu lösen?
Xvolks
also wo ist viewdidlayoutsubviewsdann? Ich dachte, es viewdidlayoutsubviewswird verwendet, um gebundene Änderungen aufgrund von Rotation zu erfassen. Können Sie das näher erläutern?
Honig
1
Wie kann man zwischen Landschaft links und Landschaft rechts unterscheiden, wenn wir keine Statusleistenorientierung verwenden? Ich brauche diese Unterscheidung. Außerdem gibt es andere Probleme, wie hier beschrieben - stackoverflow.com/questions/53364498/…
Deepak Sharma
17

Basierend auf der sehr detaillierten (und akzeptierten) Antwort von smileyborg ist hier eine Anpassung mit 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()
    })        
}

Und bei der UICollectionViewDelegateFlowLayoutUmsetzung,

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
}
CMont
quelle
11

Ich benutze einfach das Benachrichtigungscenter:

Fügen Sie eine Orientierungsvariable hinzu (wird am Ende erklärt)

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

Benachrichtigung hinzufügen, wenn Ansicht angezeigt wird

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

Benachrichtigung entfernen, wenn die Ansicht nicht mehr angezeigt wird

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

Ruft die aktuelle Ausrichtung ab, wenn eine Benachrichtigung ausgelöst wird

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

Überprüft die Ausrichtung (Hoch- / Querformat) und behandelt Ereignisse

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
        }
    }
}

Der Grund, warum ich eine Orientierungsvariable hinzufüge, ist, dass beim Testen auf einem physischen Gerät die Orientierungsbenachrichtigung bei jeder kleinen Bewegung im Gerät aufgerufen wird und nicht nur, wenn es sich dreht. Durch Hinzufügen der Anweisungen var und if wird der Code nur aufgerufen, wenn in die entgegengesetzte Ausrichtung gewechselt wurde.

unbesiegbar
quelle
11
Dies ist nicht der von Apple empfohlene Ansatz, da jede Ansicht in Ihrer App anhand der Ausrichtung des Geräts entscheidet, wie sie angezeigt werden soll, anstatt den zugewiesenen Speicherplatz zu berücksichtigen.
Smileyborg
2
Apple berücksichtigt Hardware mit 8.0 ebenfalls nicht. Sagen Sie einer AVPreview-Ebene, dass sie sich keine Gedanken über die Ausrichtung machen muss, wenn sie über einen Ansichts-Controller angezeigt wird. Funktioniert nicht, ist aber in 8.2 behoben
Nick Turner
supervon viewDidAppearund viewWillDisappearsollte genannt werden
Andrew Bogaevskyi
Hinweis: UIDeviceOrientation! = UIInterfaceOrientation. In meinen Experimenten ist statusBarOrientation nicht zuverlässig.
nnrales
2

Aus Sicht der Benutzeroberfläche glaube ich, dass die Verwendung von Größenklassen der von Apple empfohlene Ansatz für den Umgang mit Schnittstellen in verschiedenen Ausrichtungen, Größen und Maßstäben ist.

Siehe Abschnitt: Merkmale Beschreiben Sie die Größenklasse und den Maßstab einer Schnittstelle hier: https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html

"iOS 8 bietet neue Funktionen, die den Umgang mit Bildschirmgröße und -ausrichtung viel vielseitiger machen."

Dies ist auch ein guter Artikel: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

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

Aaron
quelle
Ja, es sieht so aus, als ob seine ganze Seite im Moment nicht verfügbar ist.
Aaron
Der Artikel ist in der Tat lesenswert und hier ist die richtige Adresse: carpeaqua.com/thinking-in-terms-of-ios-8-size-classes
uem
Aber was ist, wenn wir nicht über Größenklassen und Benutzeroberfläche sprechen, sondern zum Beispiel über AVFoundation? In einigen Fällen müssen Sie bei der Videoaufnahme die Ausrichtung von viewControllern kennen, um die richtigen Metadaten festzulegen. Das ist einfach unmöglich. "vielseitig".
Julian F. Weinert
Darüber hat das OP nicht gefragt / gesprochen.
Aaron
1
Aktualisierter Link: carpeaqua.com/2014/06/14/…
koen