webentwicklung-frage-antwort-db.com.de

Untergeordneter Ansichts-Controller zum Drehen, während der Elternansicht-Controller nicht funktioniert

Was ich versuche zu tun:

Übergeordnete Ansicht, die von Parent View Controller verwaltet wird SOLLTE NICHT DREHEN.

Untergeordnete Ansicht, die vom untergeordneten Ansichtscontroller SOLLTE DREHEN in alle Ausrichtungen verwaltet wird.


 enter image description here

 enter image description here


Was ich versucht habe:

ParentViewController

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return .Portrait
}

override func shouldAutorotate() -> Bool {
    return true
}

fun addChildViewController() {
    let storyBoard = UIStoryboard(name: "Main", bundle: nil)
    self.childViewController = storyBoard("Child View Controller") as? ChildViewController
    self .addChildViewController(self.childViewController!)
    self.childViewController! .didMoveToParentViewController(self)
    self.view .addSubview(self.childViewController!.view)
    self.childViewController!.view.frame = CGRectMake (40, 200, 400, 250)
}

ChildViewController

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return  .All
}

override func shouldAutorotate() -> Bool {
    return true
}

Unterstützte Ausrichtungen in Xcode Deployment Info sind auf alle vier festgelegt.

Was ich bekomme:

Keine Ansicht dreht sich. Wenn ich die Drehung des übergeordneten Elements auf "Alle" stelle, werden alle Ansichten zusammen gedreht. Also alles oder nichts.


AKTUALISIEREN

Wenn ich versuche, einen Beobachter für UIDeviceOrientationDidChangeNotification zu setzen und UIDevice.currentDevice (). Orientation zum Drehen von childView mit CGAffaineTransformMakeRotate zu verwenden, erhalte ich die gewünschten Ergebnisse. Jedoch, wenn ich in das Querformat drehe und versuche, die Benachrichtigungszentrale herunterzuziehen (oder wenn ich eine Systembenachrichtigung erhalte), die sich immer noch im Hochformat befindet (da die App nativ noch in Hochformat verbleibt), gedreht childView kehrt zum Hochformat zurück, um die Statusleiste/Benachrichtigungs-/Benachrichtigungszentrale zu berücksichtigen.

Stock iOS Camera App ist das beste Beispiel, das ich präsentieren kann. Die Hauptleinwand kann nicht in verschiedene Ausrichtungen gedreht werden, die Statusleiste jedoch dreht sich hinter den Kulissen um die Drehung der Ehrendatei. Auch die Unteransichten drehen sich um sich selbst, um unterschiedliche Orientierungen zu berücksichtigen. Ich versuche dieses Verhalten zu erreichen ....

23
Gizmodo

Nach vielen Hin- und Herbewegungen mit Apple selbst und dem Hinweis auf den gleichen Link Technische Fragen und Antworten QA1890 musste ich dies auf fließende Weise tun:

MotherViewController

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

        coordinator.animateAlongsideTransition({(context: UIViewControllerTransitionCoordinatorContext) -> Void in
            let deltaTransform: CGAffineTransform = coordinator.targetTransform()
            let deltaAngle: CGFloat = atan2(deltaTransform.b, deltaTransform.a)
            var currentRotation: CGFloat = self.mainView.layer.valueForKeyPath("transform.rotation.z") as! CGFloat

            // Adding a small value to the rotation angle forces the animation to occur in a the desired direction, preventing an issue where the view would appear to rotate 2PI radians during a rotation from LandscapeRight -> LandscapeLeft.
            currentRotation += -1 * deltaAngle + 0.0001
            self.mainView.layer.setValue(currentRotation, forKeyPath: "transform.rotation.z")

            }, completion: {(
                context: UIViewControllerTransitionCoordinatorContext) -> Void in
                // Integralize the transform to undo the extra 0.0001 added to the rotation angle.
                var currentTransform: CGAffineTransform = self.mainView.transform
                currentTransform.a = round(currentTransform.a)
                currentTransform.b = round(currentTransform.b)
                currentTransform.c = round(currentTransform.c)
                currentTransform.d = round(currentTransform.d)
                self.mainView.transform = currentTransform
        })
    }

MainViewController

NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name:UIDeviceOrientationDidChangeNotification, object: nil)

func orientationChanged ( notification: NSNotification){
        switch UIDevice.currentDevice().orientation {
        case .Portrait:
            self.rotateChildViewsForOrientation(0)
        case .PortraitUpsideDown:
            self.rotateChildViewsForOrientation(0)
        case .LandscapeLeft:
            self.rotateChildViewsForOrientation(90)
        case .LandscapeRight:
            self.rotateChildViewsForOrientation(-90)
        default:
            print ("Default")
                }
    }

Dies scheint die Unteransicht zu drehen, während die Hauptansicht statisch bleibt. Die App scheint auch die richtige Ausrichtung zu kennen, wenn Benachrichtigungen eingehen (da die Mutteransicht tatsächlich hinter den Kulissen rotiert).

Vielen Dank an jamesk und Warif Akhand Rishi für all die Hilfe!

2
Gizmodo

Der in der Kamera-App erzielte Effekt ähnelt der Verwendung einer Kombination aus:

Der technische Hinweis erläutert, dass die zugrunde liegende Implementierung der Autorotation das direkte Anwenden einer Transformation auf das Anwendungsfenster umfasst:

Die Autorotation wird durch Anwenden einer Rotationstransformation auf das Anwendungsfenster implementiert, wenn das System feststellt, dass die Schnittstelle rotieren muss. Das Fenster passt dann seine Grenzen für die neue Ausrichtung an und verbreitet diese Änderung durch Aufrufe der viewWillTransitionToSize:withTransitionCoordinator:-Methode jedes Ansichtscontrollers und des Präsentationscontrollers durch die Ansichtscontrollerhierarchie.

Beachten Sie, dass die Kamera-App die Autorotation nicht deaktiviert: Wenn Sie die Kamera-App verwenden, spiegeln die Ausrichtungen von Notification Center und Control Center die Ausrichtung des Geräts wider. Es sind nur bestimmte Ansichten innerhalb der Kamera-App, die die Autorotation zu deaktivieren scheinen. Diese Antwort legt nahe, dass solche Apps normalerweise die von AVFoundation-Klassen bereitgestellten videoGravity- und videoOrientation-Eigenschaften wie AVCaptureVideoPreviewLayer und AVCaptureConnection verwenden.

Die Vorgehensweise, die Sie ergreifen sollten, hängt davon ab, ob Sie nur das Drehen einer übergeordneten Ansicht anhalten möchten oder ob Sie einen Container-View-Controller wie UINavigationController am Drehen hindern möchten (d. H. Die Ausrichtung des Geräts sperren).

Verwenden Sie im ersten Fall die in der technischen Anmerkung beschriebene Technik, um die Ausrichtung der übergeordneten Ansicht festzulegen, und wickeln Sie (für iOS 9) umlaufende Unteransichten in eine UIStackView ein. Verwenden Sie die axis-Eigenschaft, um die Unteransichten bei der Gerätedrehung oder (für iOS) neu anzuordnen 8) Drehen Sie die Untersichten bei Gerätedrehung manuell (siehe dazu diese Antwort und diesen Beispielcode ).

In letzterem Fall ist der Ansatz auf dem richtigen Weg. Beispielcode finden Sie unter diese Antwort . Sie müssen Ihren Code und weitere Informationen zu Ihrer View Controller-Hierarchie freigeben, damit wir Quirks mit Notification Center diagnostizieren können.

Addendum: Der Grund, warum Aufrufe an shouldAutorotate und supportedInterfaceOrientations nicht an untergeordnete View-Controller weitergegeben wurden, wurde in Technische Fragen und Antworten QA1688 erläutert:

Ab iOS 6 beteiligt sich nur der oberste Ansichtscontroller (neben dem Objekt UIApplication) an der Entscheidung, ob er als Reaktion auf eine Änderung der Ausrichtung des Geräts gedreht werden soll. Meistens ist der View Controller, der Ihren Inhalt anzeigt, ein Kind von UINavigationController, UITabBarController oder einem benutzerdefinierten Container-View-Controller. Möglicherweise müssen Sie einen Container-View-Controller subclassieren, um die von den Methoden supportedInterfaceOrientations und shouldAutorotate zurückgegebenen Werte zu ändern.

In Swift können Sie diese Methoden mithilfe von Erweiterungen überschreiben .

7
jamesk

Aus der iOS-Entwicklerbibliothek Technische Fragen und Antworten

Die Autorotation wird durch Anwenden einer Rotationstransformation auf das Anwendungsfenster implementiert, wenn das System feststellt, dass die Schnittstelle rotieren muss. Das Fenster passt dann seine Grenzen für die neue Ausrichtung an und verbreitet diese Änderung durch Aufrufe an die View-Controller- und Präsentationscontroller-Methode -viewWillTransitionToSize: withTransitionCoordinator: in der View Controller-Hierarchie. Für Aufrufe dieser Methode wird ein Übergangskoordinatorobjekt bereitgestellt, das das Delta der aktuellen Transformation des Fensters und die neue Transformation enthält, die durch Senden einer -targetTransform-Nachricht an den Übergangskoordinator abgerufen werden können. Ihr View Controller oder Presentation Controller kann die entsprechende inverse Transformation ableiten und auf die Zielansicht anwenden. Dadurch wird die Auswirkung der Fenstertransformation auf diese bestimmte Ansicht aufgehoben und der Eindruck erweckt, dass die Ansicht in ihrer aktuellen Ausrichtung fixiert ist, da sich der Rest der Schnittstelle normal dreht.

wenn Sie eine Ansicht namens noRotatingView haben

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    noRotatingView.center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds))
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition({ (UIViewControllerTransitionCoordinatorContext) -> Void in

        let deltaTransform = coordinator.targetTransform()
        let deltaAngle = atan2f(Float(deltaTransform.b), Float(deltaTransform.a))

        var currentRotation = self.noRotatingView.layer.valueForKeyPath("transform.rotation.z")?.floatValue

        // Adding a small value to the rotation angle forces the animation to occur in a the desired direction, preventing an issue where the view would appear to rotate 2PI radians during a rotation from LandscapeRight -> LandscapeLeft.
        currentRotation = currentRotation! + (-1 * Float(deltaAngle)) + 0.0001
        self.noRotatingView.layer.setValue(currentRotation, forKeyPath:"transform.rotation.z")

        }) { (UIViewControllerTransitionCoordinatorContext) -> Void in

            var currentTransform = self.noRotatingView.transform;
            currentTransform.a = round(currentTransform.a);
            currentTransform.b = round(currentTransform.b);
            currentTransform.c = round(currentTransform.c);
            currentTransform.d = round(currentTransform.d);
            self.noRotatingView.transform = currentTransform;
    }
}

Ich habe versucht, ein Demo-Projekt unter https://github.com/rishi420/TestCameraRotation zu erstellen.

2