Erzwingt, dass sich die iOS-Ansicht nicht dreht, während das Kind weiterhin rotieren kann

7

Ich habe einen View-Controller mit einem Child-View-Controller.

%Vor%

A sollte gezwungen werden, immer im Portrait zu bleiben, aber B sollte sich frei drehen können.

Ich weiß, dass shouldAutorotate für alle View-Controller und ihre Kinder gilt, aber gibt es eine Möglichkeit, dies zu umgehen? Es scheint, als könnte ich shouldAutorotateToInterfaceOrientation verwenden, aber das ist in iOS 8 blockiert.

Ich möchte einen Videoplayer statisch halten (horizontale Videos sind unabhängig von der Ausrichtung des Geräts immer horizontal), während das Overview-Overlay der Steuerschicht frei rotieren darf.

Ich benutze Swift.

    
switz 02.02.2015, 12:44
quelle

6 Antworten

17

Ich hatte genau dieses Problem und fand schnell heraus, dass es eine Menge schlechter Ratschläge bezüglich Autorotation gibt, besonders weil iOS 8 anders damit umgeht als frühere Versionen.

Zunächst möchten Sie nicht eine Gegenrotation manuell anwenden oder UIDevice -Orientierungsänderungen abonnieren. Eine Gegenrotation führt immer noch zu einer unschönen Animation, und die Ausrichtung Gerät entspricht nicht immer der Ausrichtung Schnittstelle . Im Idealfall möchten Sie, dass die Vorschau der Kamera wirklich eingefroren bleibt und die Benutzeroberfläche der App der Ausrichtung und Größe der Statusleiste bei ihrer Änderung entspricht, genau wie die native Kamera-App.

Während einer Orientierungsänderung in iOS 8 rotiert das Fenster selbst und nicht die darin enthaltenen Ansichten. Sie können die Ansichten mehrerer View-Controller zu einem einzelnen UIWindow hinzufügen, aber nur der rootViewController erhält eine Möglichkeit, über shouldAutorotate() zu antworten. Obwohl Sie die Rotationsentscheidung auf der Ebene des Ansichtscontrollers treffen, dreht sich tatsächlich das übergeordnete Fenster, wodurch alle Unteransichten (einschließlich der Ansichten anderer Ansichtscontroller) gedreht werden.

Die Lösung besteht aus zwei UIWindow , die übereinander gestapelt sind und sich jeweils mit einem eigenen Root-View-Controller drehen (oder nicht). Die meisten Apps haben nur eine, aber es gibt keinen Grund, warum du nicht zwei haben und sie wie jede andere UIView -Unterklasse überlagern kannst.

Hier ist ein funktionierender Proof-of-Concept, den ich hier ebenfalls auf GitHub gesetzt habe . Ihr spezieller Fall ist etwas komplizierter, weil Sie einen Stapel mit View-Controllern haben, aber die Grundidee ist dieselbe. Ich werde auf einige spezifische Punkte unten eingehen.

%Vor%

Wenn Sie einen negativen Inset auf interfaceWindow setzen, wird die schwarze rechteckige Maske, die Sie sonst sehen würden, etwas größer als die Bildschirmgrenzen. Normalerweise würden Sie das nicht bemerken, weil sich die Maske mit dem Fenster dreht, aber da das Kamerafenster fixiert ist, wird die Maske während der Drehung in den Ecken sichtbar.

%Vor%

Genau das, was Sie hier erwarten würden, fügen Sie einfach Ihr eigenes Setup für AVCapturePreviewLayer hinzu.

%Vor%

Der letzte Trick ist das Rückgängigmachen des negativen Einschubs, den wir auf das Fenster angewendet haben, was wir erreichen, indem wir view um den gleichen Betrag versetzen und contentView als Hauptansicht behandeln.

Für Ihre App wäre interfaceWindow.rootViewController Ihr Tab-Bar-Controller, der wiederum einen Navigations-Controller usw. enthält. Alle diese Ansichten müssen transparent sein, wenn Ihr Kamera-Controller erscheint, damit das Kamera-Fenster darunter durchscheinen kann. Aus Performance-Gründen sollten Sie sie undurchsichtig lassen und nur dann alles transparent machen, wenn die Kamera tatsächlich verwendet wird, und das Kamerafenster auf hidden stellen, wenn dies nicht der Fall ist (und gleichzeitig die Aufnahmesitzung beenden).

Es tut mir leid, einen Roman zu veröffentlichen; Ich habe das nirgendwo anders gesehen gesehen und es hat eine Weile gedauert, bis ich herausgefunden habe, hoffentlich hilft es dir und allen anderen, die versuchen, das gleiche Verhalten zu bekommen. Selbst Apples AVCam Beispiel-App geht damit nicht richtig um.

Das Beispiel-Repo, das ich gepostet habe , enthält auch eine Version, bei der die Kamera bereits eingerichtet ist. Viel Glück!

    
jstn 01.03.2015, 17:27
quelle
1

Sie können das versuchen -

Objective-C-Code, wenn Sie eine Alternative in swift haben:

%Vor%     
Kumar 02.02.2015 15:12
quelle
1

Sie können Rotationsänderungsbenachrichtigungen abonnieren und die Rotationsumwandlungsmatrix für die Unteransicht, die Sie drehen möchten, manuell festlegen.

    
rounak 01.03.2015 07:33
quelle
0

Ich bin mir nicht sicher, aber ich denke, Sie könnten eine eigene Klasse für Ihre Unteransicht erstellen und die shouldAutorotate -Methode usw. überschreiben. Auf diese Weise sollte die shouldAutorotate vom Parent-View-Controller überschrieben werden.

    
Christian 02.02.2015 12:46
quelle
0

Kurze Antwort: Nein, alle sichtbaren Controller und Ansichten rotieren (oder rotieren nicht) zusammen.

Lange Antwort:

Zuerst müssen Sie Autorotate-Entscheidungsfunktionen im Stammcontroller implementieren. das kann bedeuten, eine Nav-Controller-Unterklasse zu erstellen.

Sie können Ihr gewünschtes Verhalten hacken, indem Sie die Elternansicht automatisch drehen lassen - aber Sie müssen es manuell drehen zurück , um nicht gedreht zu erscheinen.

Oder Sie können nicht automatisch eine automatische Drehauswahl durchführen, sondern auf Benachrichtigungen achten, die das physische Gerät gedreht hat, und die gewünschten Ansichten manuell drehen, zB: Replizierung der Kamera-App-Rotation auf Landschaft IOS 6 iPhone

Siehe auch, fyi:

Erzwingen, dass ein UIViewController zu Portrait wird Orientierung in iOS 6

shouldAutoRotate-Methode, die in iOS6 nicht aufgerufen wird

iOS6: supportedInterfaceOrientations funktioniert nicht (wird aufgerufen, aber die Schnittstelle dreht sich immer noch)

Wie die UIViewController-Rotation als Reaktion auf die Ausrichtung implementiert wird Änderungen?

    
Ben Wheeler 01.03.2015 07:58
quelle
0

Die einfachste und geradlinigste Antwort auf diese Frage ist die Betrachtung von Apples AVCam Beispiel Code. Die wichtigsten Teile für mich waren, dass es:

  1. Verwendet eine Ansicht, deren layerClass AVCaptureVideoPreviewLayer ist.
  2. Setzt die videoOrientation der AVCaptureVideoPreviewLayer-Verbindung auf die statusBarOrientation der Anwendung, wenn die Ansicht angezeigt wird, im Wesentlichen viewWillAppear(_:) .
  3. Setzt videoOrientation auf UIDevice.currentDevice().orientation in viewWillTransitionToSize(_:withTransitionCoordinator:) .
  4. Aktiviert Autorotation und unterstützt alle Schnittstellenausrichtungen.

Ich habe den von jstn beschriebenen Ansatz des Hintergrundfensters implementiert und es hat ziemlich gut funktioniert, aber in Wirklichkeit ist es viel komplizierter als nötig. AVCam funktioniert gut und hat einen relativ einfachen Ansatz.

    
Adam Preble 30.09.2015 19:07
quelle