Wie erzwinge ich die Ausrichtung des View Controllers in iOS 8?


149

Vor iOS 8 haben wir den folgenden Code in Verbindung mit unterstützten Delegate-Methoden von InterfaceOrientations und shouldAutoRotate verwendet, um die App-Ausrichtung auf eine bestimmte Ausrichtung zu erzwingen. Ich habe das folgende Code-Snippet verwendet, um die App programmgesteuert in die gewünschte Ausrichtung zu drehen. Erstens ändere ich die Ausrichtung der Statusleiste. Wenn Sie dann nur eine modale Ansicht präsentieren und sofort schließen, wird die Ansicht in die gewünschte Ausrichtung gedreht.

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];

Dies schlägt jedoch in iOS 8 fehl. Außerdem habe ich einige Antworten im Stapelüberlauf gesehen, bei denen vorgeschlagen wurde, diesen Ansatz ab iOS 8 immer zu vermeiden.

Genauer gesagt ist meine Bewerbung eine universelle Art der Bewerbung. Insgesamt gibt es drei Controller.

  1. First View-Controller - Er sollte alle Ausrichtungen auf dem iPad und nur Hochformat (Home-Taste gedrückt) auf dem iPhone unterstützen.

  2. Second View-Controller - Er sollte unter allen Bedingungen nur Landschaftsrechte unterstützen

  3. Third View Controller - Er sollte unter allen Bedingungen nur Landschaftsrechte unterstützen

Wir verwenden den Navigationscontroller für die Seitennavigation. Vom ersten Ansichtscontroller aus schieben wir auf Knopfdruck den zweiten auf den Stapel. Wenn der zweite Ansichts-Controller unabhängig von der Geräteorientierung eintrifft, sollte die App nur im Querformat richtig einrasten.

Unten ist meine shouldAutorotateund supportedInterfaceOrientationsMethoden in der zweiten und dritten Ansicht Controller.

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

Gibt es eine Lösung für diese oder eine bessere Möglichkeit, einen View Controller in einer bestimmten Ausrichtung für iOS 8 zu sperren? Bitte helfen Sie !!


Die Implementierung der Methoden, die Sie in der vorgestellten VC erwähnt haben, sollte im Allgemeinen funktionieren (zumindest ist dies meine Erfahrung in iOS 8). Vielleicht verursacht Ihr spezielles Setup Probleme?
Vladimir Gritsenko

Vielleicht kann ich die Frage etwas klarer machen. Ich werde die Frage leicht bearbeiten.
Rashmi Ranjan Mallick

@VladimirGritsenko: Bitte überprüfen Sie jetzt. Ich habe es bearbeitet.
Rashmi Ranjan Mallick

Der Code in der Frage verwendet nicht den Stack des Navigationscontrollers, sondern die modale Darstellung, sodass immer noch nicht klar ist, was Sie genau tun. Ich werde sagen, dass in unserem Code die Rückgabe von YES von shouldAutoRotate und die Rückgabe der gewünschten Ausrichtungen von supportInterfaceOrientations in der dargestellten VC diese VC richtig ausrichtet.
Vladimir Gritsenko

Nun, es ist nicht wirklich ein Misserfolg, es ist nur eine große Änderung im Konzept. Ob es eine gute Veränderung ist, ist ein ganz anderes Thema.
Kegluneq

Antworten:


315

Für iOS 7 - 10:

Ziel c:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];

Swift 3:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()

Rufen Sie es einfach im - viewDidAppear:vorgestellten View Controller auf.


61
Dies ist keine private API. Dies ist eine unsichere Verwendung von APIs. Sie verwenden keine privaten Methoden, sondern 'interne Dinge'. Wenn Apple den Wert für "Ausrichtung" ändert, schlägt dies fehl. Schlimmer noch: Wenn Apple die Bedeutung des Werts "Ausrichtung" ändert, wissen Sie nicht, was Sie ändern, wenn Sie den Wert hart einstellen.
Sonxurxo

4
Um die Animation zu deaktivieren, setzen Sie sie [UIView setAnimationsEnabled:NO];ein viewWillAppearund [UIView setAnimationsEnabled:YES];aus viewDidAppear, im Zusammenhang mit: stackoverflow.com/a/6292506/88597
ohho

3
Netter Hack, aber das Problem dabei ist, dass die didRotateFromInterfaceOrientation nicht ausgelöst wird, nachdem der neue Orientierungswert (Seufzer) eingestellt wurde
loretoparisi

2
In iOS 9.2 ändert dies nur die Ausrichtung, nicht jedoch das Sperren.
Mark13426

2
Für alle, die sich in 90% der Fälle gut verhalten und in den anderen 10% der [UINavigationController attemptRotationToDeviceOrientation];
Albert Renshaw

93

Die Orientierungsrotation ist etwas komplizierter, wenn Sie sich in einem UINavigationControlleroder befinden UITabBarController. Das Problem besteht darin, dass, wenn ein Ansichts-Controller in einen dieser Controller eingebettet ist, der Navigations- oder Registerkarten-Controller Vorrang hat und Entscheidungen über Autorotation und unterstützte Ausrichtungen trifft.

Ich verwende die folgenden 2 Erweiterungen für UINavigationController und UITabBarController, damit View-Controller, die in einen dieser Controller eingebettet sind, die Entscheidungen treffen können.

Geben Sie View Controllern die Kraft!

Swift 2.3

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

extension UITabBarController {
    public override func supportedInterfaceOrientations() -> Int {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

Swift 3

extension UINavigationController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
    }
}

extension UITabBarController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

Jetzt können Sie die supportedInterfaceOrientationsMethode überschreiben oder shouldAutoRotateden View Controller, den Sie sperren möchten, überschreiben. Andernfalls können Sie die Überschreibungen in anderen View Controllern weglassen, die das in der Liste Ihrer App angegebene Standardausrichtungsverhalten erben möchten

Drehung deaktivieren

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

Auf spezifische Ausrichtung festlegen

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

Theoretisch sollte dies für alle komplexen View Controller-Hierarchien funktionieren, aber ich habe ein Problem mit UITabBarController festgestellt. Aus irgendeinem Grund möchte es einen Standardausrichtungswert verwenden. Lesen Sie den folgenden Blog-Beitrag, wenn Sie erfahren möchten, wie Sie einige der Probleme umgehen können:

Bildschirmdrehung sperren


1
Ich weiß, dass dies ein sehr alter Beitrag ist, aber wo würden Sie den Erweiterungscode platzieren?
Dwinnbrown

7
Abwärtsmarkierung für eine Swift-Antwort nur auf eine Objective-C-Frage.
Charlie Scott-Skinner

17
Dies ist eine schöne Lösung für Swift und ObjC. Verstehe nicht, warum Leute abstimmen. Sie haben die Idee und dann ist das Schreiben von Code einfach. Warum sich beschweren?
Zhao

2
@Krodak, versuchen Sie in den Erweiterungen "-> Int" in "-> UIInterfaceOrientationMask" zu ändern. Hat den Trick für mich gemacht.
the_pantless_coder

2
Die Idee und der Code sind perfekt, ich liebe es, aber es gibt ein Problem bei der Verwendung von UINavigationController und beim Zurückkehren von einem UIViewController im Querformat zu einem UIViewController, der im Hochformat angezeigt werden muss. Irgendwelche Ideen?
KriseGriega

24

Das hat bei mir funktioniert:

https://developer.apple.com/library//ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation

Rufen Sie es in Ihrer viewDidAppear: -Methode auf.

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [UIViewController attemptRotationToDeviceOrientation];
}

3
Sehr nützlich, wenn das Gerät bereits gedreht ist und Sie Ihren View Controller drehen müssen
avdyushin

2
Gute Antwort. In Kombination mit der akzeptierten Antwort funktioniert dies jedes Mal gut für mich in Swift und iOS 9+.
AndyDunn

1
Ich denke zwar, es ist nicht die Antwort auf die gestellte Frage, aber es hat mir wirklich geholfen.
Abdurrahman Mubeen Ali

21

Ich habe festgestellt, dass Sie überschreiben können, wenn es sich um einen präsentierten Ansichts-Controller handelt preferredInterfaceOrientationForPresentation

Schnell:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

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

4
Es scheint, dass die akzeptierte Antwort einfach einen Orientierungswechsel zur Landschaft auslöst. Was Sie hier gezeigt haben, ist, wie Sie einen Ansichts-Controller dazu zwingen , sich nur im Querformat zu befinden und den darstellenden Ansichts-Controller nicht zu beeinflussen (genau das, was ich brauche). Vielen Dank.
Clifton Labrum

1
@ CliftonLabrum hast du noch etwas getan, um nur Landschaft zu erzwingen ? Mit demselben Code kann der Ansichtscontroller weiterhin in eine andere Ausrichtung gedreht werden.
Crashalot

Ich habe später gemerkt, dass - Sie haben Recht. Ich habe noch keine Lösung gefunden.
Clifton Labrum

1
Das hat bei mir funktioniert. Mit diesem Code konnte ich einen einzelnen View Controller im Hochformatmodus halten (Landscape durch Portrait ersetzen). +1
Mark Barrasso

Ja! Dies funktionierte auch für mich in Xcode 7.3 & Swift 2.2. Sie müssen jedoch noch die func-Anwendung für supportInterfaceOrientationsForWindow in AppDelegate definieren.
charles.cc.hsu

15

So funktioniert es für mich in Swift 2 iOS 8.x:

PS (diese Methode erfordert nicht das Überschreiben von Orientierungsfunktionen wie shouldautorotate auf jedem viewController, nur eine Methode auf AppDelegate)

Aktivieren Sie das Kontrollkästchen "Vollbild erforderlich" in den allgemeinen Projektinformationen. Geben Sie hier die Bildbeschreibung ein

Machen Sie also auf AppDelegate.swift eine Variable:

var enableAllOrientation = false

Also, setzen Sie auch diese Funktion:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if (enableAllOrientation == true){
            return UIInterfaceOrientationMask.All
        }
        return UIInterfaceOrientationMask.Portrait
}

In jeder Klasse in Ihrem Projekt können Sie diese Variable in viewWillAppear festlegen:

override func viewWillAppear(animated: Bool)
{
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.enableAllOrientation = true
}

Wenn Sie eine Auswahl basierend auf dem Gerätetyp treffen müssen, können Sie Folgendes tun:

override func viewWillAppear(animated: Bool)
    {
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        switch UIDevice.currentDevice().userInterfaceIdiom {
        case .Phone:
        // It's an iPhone
           print(" - Only portrait mode to iPhone")
           appDelegate.enableAllOrientation = false
        case .Pad:
        // It's an iPad
           print(" - All orientation mode enabled on iPad")
           appDelegate.enableAllOrientation = true
        case .Unspecified:
        // Uh, oh! What could it be?
           appDelegate.enableAllOrientation = false
        }
    }

sehr schöne Erklärung
Mihir Oza

11

Zuallererst - dies ist im Allgemeinen eine schlechte Idee, da etwas mit Ihrer App-Architektur nicht stimmt. In diesem Fall sh..t happenskönnen Sie jedoch versuchen, Folgendes zu erstellen:

final class OrientationController {

    static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]

    // MARK: - Public

    class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
        OrientationController.allowedOrientation = [orientationIdiom]
    }

    class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
        var mask:UIInterfaceOrientationMask = []
        switch orientation {
            case .unknown:
                mask = [.all]
            case .portrait:
                mask = [.portrait]
            case .portraitUpsideDown:
                mask = [.portraitUpsideDown]
            case .landscapeLeft:
                mask = [.landscapeLeft]
            case .landscapeRight:
                mask = [.landscapeRight]
        }

        OrientationController.lockOrientation(mask)

        UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
    }
}

Als in AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // do stuff
    OrientationController.lockOrientation(.portrait)
    return true
}

// MARK: - Orientation

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return OrientationController.allowedOrientation
}

Und wann immer Sie die Ausrichtung ändern möchten, gehen Sie wie folgt vor:

OrientationController.forceLockOrientation(.landscapeRight)

Hinweis: Manchmal wird das Gerät möglicherweise nicht von einem solchen Anruf aktualisiert. Daher müssen Sie möglicherweise die folgenden Schritte ausführen

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)

Das ist alles


9

Dies sollte ab iOS 6 funktionieren, aber ich habe es nur unter iOS 8 getestet. Unterklassen UINavigationControllerund überschreiben Sie die folgenden Methoden:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}

Oder fragen Sie den Controller für sichtbare Ansichten

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}

- (BOOL)shouldAutorotate {
    return self.visibleViewController.shouldAutorotate;
}

und implementieren Sie die Methoden dort.


Ich habe dies gerade auf meiner App in Xcode 8.2.1 unter iOS 10.0 getestet und es funktioniert. Mein Spielmenü ist der erste Bildschirm, der sich nicht dreht. Alle anderen Ansichten drehen sich. Perfekt! Hat es geschafft. Ich brauchte nur die von Mojo66 bereitgestellte Funktion 'PreferredInterfaceOrientationForPresentation'.
Philip Borges

9

Dies ist ein Feedback zu Kommentaren in Sid Shahs Antwort zum Deaktivieren von Animationen mit:

[UIView setAnimationsEnabled:enabled];

Code:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:NO];
    [UIView setAnimationsEnabled:NO];

    // Stackoverflow #26357162 to force orientation
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:NO];
    [UIView setAnimationsEnabled:YES];
}

Wie kann ich das für Portrait verwenden?
Muju

6

Wenn Sie navigationViewController verwenden, sollten Sie hierfür eine eigene Oberklasse erstellen und überschreiben:

- (BOOL)shouldAutorotate {
  id currentViewController = self.topViewController;

  if ([currentViewController isKindOfClass:[SecondViewController class]])
    return NO;

  return YES;
}

Dadurch wird die Drehung in SecondViewController deaktiviert. Wenn Sie jedoch Ihren SecondViewController drücken, während sich Ihr Gerät im Hochformat befindet, wird Ihr SecondViewController im Hochformat angezeigt .

Angenommen, Sie verwenden ein Storyboard. Sie müssen einen manuellen Übergang ( How to ) und in Ihrer "onClick" -Methode erstellen:

- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
  NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
  [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
  [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}

Dadurch wird die Ausrichtung im Querformat erzwungen, bevor die Superklasse die Autorotate-Funktion deaktiviert.


6

Da Xcode 8die Methoden in Eigenschaften konvertiert werden, funktioniert folgendes mit Swift:

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}

override public var shouldAutorotate: Bool {
    return true
}

Sperrt dies die Ausrichtung?
Bnussey

1
@bnussey Ich wollte die automatische Rotation verhindern und immer im portraitModus sein, egal wie die Ausrichtung auf dem iPad ist. Mit der shouldAutorotateRückgabe von true habe ich das erreicht.
Ali Momen Sani

4

Ich habe viele Lösungen ausprobiert, aber die, für die ich gearbeitet habe, ist die folgende:

Es ist nicht erforderlich, die info.plistin ios 8 und 9 zu bearbeiten .

- (BOOL) shouldAutorotate {
    return NO;
}   

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}

Mögliche Orientierungen aus der Apple-Dokumentation :

UIInterfaceOrientationUnknown

Die Ausrichtung des Geräts kann nicht bestimmt werden.

UIInterfaceOrientationPortrait

Das Gerät befindet sich im Hochformat, wobei das Gerät aufrecht gehalten und die Home-Taste unten gedrückt wird.

UIInterfaceOrientationPortraitUpsideDown

Das Gerät befindet sich im Hochformat, jedoch auf dem Kopf stehend. Das Gerät wird aufrecht gehalten und die Home-Taste oben.

UIInterfaceOrientationLandscapeLeft

Das Gerät befindet sich im Querformat, wobei das Gerät aufrecht gehalten wird und sich die Home-Taste auf der linken Seite befindet.

UIInterfaceOrientationLandscapeRight

Das Gerät befindet sich im Querformat, wobei das Gerät aufrecht gehalten wird und sich die Home-Taste auf der rechten Seite befindet.


3

Die Kombination von Sids- und Koreys-Antworten hat bei mir funktioniert.

Erweiterung des Navigationscontrollers:

extension UINavigationController {
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

Deaktivieren Sie dann die Drehung in der Einzelansicht

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

Und vor dem Übergang in die richtige Ausrichtung drehen

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "SomeSegue")
    {
        let value = UIInterfaceOrientation.Portrait.rawValue;
        UIDevice.currentDevice().setValue(value, forKey: "orientation")
    }
}

Wissen Sie, ob dies meinem Problem helfen könnte, wenn sich der angezeigte Ansichts-Controller eine Sekunde lang im Querformat befindet, bevor er sich wie immer im Hochformat dreht? Frage ist hier: stackoverflow.com/questions/30693964/…
Dwinnbrown

3

Die Top-Lösung oben:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

hat bei mir nicht funktioniert, als ich es in viewDidAppear des vorgestellten View Controllers aufgerufen habe. Es hat jedoch funktioniert, als ich es in prepareForSegue im Presenting View Controller aufgerufen habe.

(Entschuldigung, nicht genug Reputationspunkte, um diese Lösung zu kommentieren, also musste ich sie so hinzufügen)


Ich habe dies zum Laufen gebracht, aber wenn Sie von einem Querformat-Ansichts-Controller zu einem Hochformat-Ansichts-Controller wechseln, wird der Ansichts-Controller, der im Hochformat angezeigt werden soll, kurz im Querformat angezeigt, bevor er sich selbst dreht. Wenn jemand weiß, wie er meiner Frage helfen kann, ist hier: stackoverflow.com/questions/30693964/…
dwinnbrown

@dwinnbrown at viewDidAppear Der View Controller ist bereits sichtbar. Vielleicht versuchen Sie es stattdessen mit viewDidLoad?
Crashalot

@Crashalot Ich habe das jetzt behoben. Bitte beachten Sie die Antwort, die ich als richtig markiert habe.
Dwinnbrown

@ Dwinnbrown Der Link zu Ihrer Frage ist tot. aktualisieren? Vielen Dank!
Crashalot

@Crashalot die Community hat es gelöscht, aber ich habe dafür gestimmt, es wiederherzustellen. Ich werde Sie bald wissen lassen
Dwinnbrown

3

[iOS9 +] Wenn jemand den ganzen Weg nach unten gezogen hat, da keine der oben genannten Lösungen funktioniert hat, und wenn Sie die Ansicht präsentieren, die Sie nach Segue ändern möchten, sollten Sie dies überprüfen.

Überprüfen Sie den Präsentationstyp Ihres Segues. Meins war "über dem aktuellen Kontext". Als ich es in Vollbild geändert habe, hat es funktioniert.

Dank @GabLeRoux habe ich diese Lösung gefunden.

  • Diese Änderung funktioniert nur in Kombination mit den oben genannten Lösungen.

2

Meine Anforderungen sind

  1. Sperren Sie alle Ansichten im Hochformat
  2. Verwenden Sie AVPlayerViewControllerdiese Option, um Videos abzuspielen

Wenn es sich bei der Wiedergabe eines Videos um eine Landschaft handelt, kann der Bildschirm die Landschaft nach rechts und die Landschaft nach links drehen. Wenn es sich um ein Porträt handelt, sperren Sie die Ansicht nur im Hochformat.

Definieren Sie zunächst supportedInterfaceOrientationsForWindowinAppDelegate.swift

var portrait = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if portrait {
        return .Portrait
    } else {
        return .Landscape
    }
}

Zweitens definieren Sie in Ihrem Hauptansichts-Controller die folgenden Funktionen

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    print("\(#function)")
    return .Portrait
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return .Portrait
}

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

Dann müssen Sie eine Unterklasse erstellen AVPlayerViewController

class MyPlayerViewController: AVPlayerViewController {

    var size: CGSize?

    var supportedOrientationMask: UIInterfaceOrientationMask?
    var preferredOrientation: UIInterfaceOrientation?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let size = size {
            if size.width > size.height {
                self.supportedOrientationMask =[.LandscapeLeft,.LandscapeRight]
                self.preferredOrientation =.LandscapeRight
            } else {
                self.supportedOrientationMask =.Portrait
                self.preferredOrientation =.Portrait
            }
        }
    }

Überschreiben Sie diese drei Funktionen in MyPlayerViewController.swift

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return self.supportedOrientationMask!
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return self.preferredOrientation!
}

Da der Benutzer die Gerätelandschaft möglicherweise nach links oder rechts drehen kann, müssen wir die automatische Drehung auf true setzen

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

Erstellen Sie MyPlayerViewControllerabschließend eine Instanz in Ihrem Ansichts-Controller und legen Sie den Wert für die Eigenschaftsgröße fest.

let playerViewController = MyPlayerViewController()

// Get the thumbnail  
let thumbnail = MyAlbumFileManager.sharedManager().getThumbnailFromMyVideoMedia(......)

let size = thumbnail?.size
playerViewController.size = size

Initiieren Sie Ihren Player mit dem richtigen videoUrlund weisen Sie Ihren Player dann zu playerViewController. Viel Spaß beim Codieren!


2
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [UIViewController attemptRotationToDeviceOrientation];
}

1

Es scheint immer noch eine Debatte darüber zu geben, wie diese Aufgabe am besten erfüllt werden kann, daher dachte ich, ich würde meinen (Arbeits-) Ansatz teilen. Fügen Sie Ihrer UIViewControllerImplementierung den folgenden Code hinzu :

- (void) viewWillAppear:(BOOL)animated
{
    [UIViewController attemptRotationToDeviceOrientation];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

-(BOOL)shouldAutorotate
{
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft;
}

In diesem Beispiel müssen Sie in Ihren Projekteinstellungen (oder direkt in info.plist) auch die zulässigen Geräteorientierungen auf "Querformat links" setzen . Ändern Sie einfach die spezifische Ausrichtung, die Sie erzwingen möchten, wenn Sie etwas anderes als möchtenLandscapeLeft.

Der Schlüssel für mich war der attemptRotationToDeviceOrientationAnruf viewWillAppear- ohne das würde sich die Ansicht nicht richtig drehen, ohne das Gerät physisch zu drehen.


Veraltete Methode.
Saqib Omer

1

Nach der Antwort von Korey Hinton

Swift 2.2:

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return visibleViewController!.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController!.shouldAutorotate()
    }
}


extension UITabBarController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

Drehung deaktivieren

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

Auf spezifische Ausrichtung festlegen

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

1

Ich habe hier ein paar Lösungen ausprobiert und es ist wichtig zu verstehen, dass es der Root-View-Controller ist, der bestimmt, ob er sich dreht oder nicht.

Ich habe das folgende Objective-C- Projekt erstellt: github.com/GabLeRoux/RotationLockInTabbedViewChild mit einem Arbeitsbeispiel für ein Projekt, bei dem eine untergeordneteTabbedViewController Ansicht gedreht werden darf und die andere untergeordnete Ansicht im Hochformat gesperrt ist.

Es ist nicht perfekt, aber es funktioniert und die gleiche Idee sollte für andere Arten von Root-Ansichten wie funktionieren NavigationViewController. :) :)

Die untergeordnete Ansicht sperrt die übergeordnete Ausrichtung


0

Laut der von @ sid-sha gezeigten Lösung müssen Sie alles in die viewDidAppear:Methode einfügen, sonst werden Sie nicht didRotateFromInterfaceOrientation:gefeuert, also so etwas wie:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
        interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        NSNumber *value = [NSNumber numberWithInt:interfaceOrientation];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}

0

Meine Lösung

In AppDelegate:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if let topController = UIViewController.topMostViewController() {
        if topController is XXViewController {
            return [.Portrait, .LandscapeLeft]
        }
    }
    return [.Portrait]
}

XXViewController ist der ViewController, den Sie im Querformat unterstützen möchten.

Dann würde die Lösung von Sunny Shah in XXViewControllerjeder iOS-Version funktionieren :

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

Dies ist die Dienstprogrammfunktion, um den obersten ViewController zu finden.

extension UIViewController {

    /// Returns the current application's top most view controller.
    public class func topMostViewController() -> UIViewController? {
        let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
        return self.topMostViewControllerOfViewController(rootViewController)
    }



    /// Returns the top most view controller from given view controller's stack.
    class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
        // UITabBarController
        if let tabBarController = viewController as? UITabBarController,
           let selectedViewController = tabBarController.selectedViewController {
            return self.topMostViewControllerOfViewController(selectedViewController)
        }

        // UINavigationController
        if let navigationController = viewController as? UINavigationController,
           let visibleViewController = navigationController.visibleViewController {
            return self.topMostViewControllerOfViewController(visibleViewController)
        }

        // presented view controller
        if let presentedViewController = viewController?.presentedViewController {
            return self.topMostViewControllerOfViewController(presentedViewController)
        }

        // child view controller
        for subview in viewController?.view?.subviews ?? [] {
            if let childViewController = subview.nextResponder() as? UIViewController {
                return self.topMostViewControllerOfViewController(childViewController)
            }
        }

        return viewController
    }

}

0

Verwenden Sie diese Option, um die Ausrichtung des Ansichtscontrollers zu sperren, der unter IOS 9 getestet wurde:

// Ausrichtung auf Querformat rechts sperren

-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
    return UIInterfaceOrientationMaskLandscapeRight;
}

0

Ich habe das gleiche Problem und verschwende so viel Zeit dafür. Jetzt habe ich meine Lösung. Meine App-Einstellung unterstützt nur Hochformat. Einige Bildschirme in meiner App benötigen jedoch nur Querformat. Ich behebe dies, indem ich eine Variable isShouldRotate bei AppDelegate habe . Und die Funktion bei AppDelegate :

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    if isShouldRotate == true {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

Und schließlich, wenn ein ViewControllerA einen Landschaftsstatus benötigt. Genau das tun: vor Push / present zu ViewControllerA assign isShouldRotate zu wahren . Vergessen Sie nicht, wenn Pop / Entlassen , das der Controller zuweist , bei viewWillDisappear isShouldRotate auf false ist .


0

Für mich musste der VC der obersten Ebene die Orientierungsüberschreibungen implementieren. Die Verwendung von VCs im Stack hat keine Auswirkung, wenn die oberste VC nicht implementiert wird.

VC-main
    |
    -> VC 2
        |
        -> VC 3

Im Wesentlichen in meinen Tests wird nur VC-Main angehört.


0

Es sieht so aus, als ob selbst du hier so viele Antworten hast, dass mir niemand gereicht hat. Ich wollte die Orientierung erzwingen und dann beim [UIViewController attemptRotationToDeviceOrientation];Zurückkehren zur Geräteorientierung zurückkehren, funktionierte aber einfach nicht. Was das Ganze auch kompliziert gemacht hat, ist, dass ich shouldAutorotate basierend auf einer Antwort zu false hinzugefügt habe und nicht die gewünschten Effekte erzielen konnte, um in allen Szenarien korrekt zurückzudrehen.

Das habe ich also getan:

Bevor Sie den Controller in seinem Init-Konstruktor aufrufen, gehen Sie wie folgt vor:

_userOrientation = UIDevice.currentDevice.orientation;
[UIDevice.currentDevice setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
[self addNotificationCenterObserver:@selector(rotated:)
                               name:UIDeviceOrientationDidChangeNotification];

Also speichere ich die letzte Geräteorientierung und registriere mich für das Orientierungsänderungsereignis. Ein Orientierungsänderungsereignis ist einfach:

- (void)rotated:(NSNotification*)notification {
    _userOrientation = UIDevice.currentDevice.orientation;
}

Und auf den ersten Blick zwinge ich einfach zu jeder Orientierung zurück, die ich als userOreintation habe:

- (void)onViewDismissing {
    super.onViewDismissing;
    [UIDevice.currentDevice setValue:@(_userOrientation) forKey:@"orientation"];
    [UIViewController attemptRotationToDeviceOrientation];
}

Und das muss auch da sein:

- (BOOL)shouldAutorotate {
    return true;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

Und auch der Navigationscontroller muss an shouldAutorotate delegieren undInterfaceOrientations unterstützen, aber das glauben die meisten Leute bereits.

PS: Tut mir leid, ich verwende einige Erweiterungen und Basisklassen, aber Namen sind ziemlich aussagekräftig, so dass das Konzept verständlich ist und noch mehr Erweiterungen ergibt, da es jetzt nicht zu hübsch ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.