Erzwingen Sie den Landschaftsmodus in einem ViewController mit Swift

73

Ich versuche, im Querformat nur eine Ansicht in meiner Anwendung zu erzwingen, die ich anrufe

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

override func supportedInterfaceOrientations() -> Int {
    print("supportedInterfaceOrientations")
    return Int(UIInterfaceOrientationMask.LandscapeLeft.rawValue)
}

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

Die Ansicht wird im Hochformat gestartet und dreht sich weiter, wenn ich die Ausrichtung des Geräts ändere.
Das shouldAutorotate wird niemals aufgerufen.
Jede Hilfe wäre dankbar.

sazz
quelle

Antworten:

80

Es kann für andere nützlich sein. Ich habe einen Weg gefunden, die Ansicht im Querformat zu starten:

Fügen Sie dies in viewDidLoad () ein:

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

und,

override var shouldAutorotate: Bool {
    return true
}
sazz
quelle
5
Ich habe es gerade versucht und es hat nicht funktioniert. obwohl das Ändern von shouldAutorotate () so geändert wurde, dass es falsch funktioniert. Um ganz klar zu sein: Ich wollte, dass es in Portrait bleibt, egal was passiert. (Auch UIInterfaceOrientation.LandscapeLeft in UIInterfaceOrientation.Portrait natürlich geändert)
milo526
2
Dies liegt daran, dass Ihre Ansicht im Hochformat geladen wird und Sie möchten, dass sie so bleibt. Meine Ansicht wird im Hochformat geladen und ich möchte, dass sie im Querformat angezeigt wird. Wenn ich sollteAutorotate auf NEIN setzen, wird es nicht in Landschaft
angezeigt
Vielen Dank!! Dies funktionierte hervorragend für mich in einer iOS9-App mit Swift 2.2, um das Porträt zu erzwingen. Ich habe mit einer übergeordneten Ansicht im Querformat begonnen, den obigen Code in viewDidLoad des ViewControllers eingefügt, den ich modal vom übergeordneten Element aus präsentiere, und als die modale Ansicht dargestellt wurde, wurde die Ansicht in Hochformat gedreht. Als ich die Modalansicht verwarf, blieb das 'Elternteil' im Hochformat (obwohl ich wetten konnte, dass Sie einen Wert für die 'vorherige Ausrichtung' speichern konnten, bevor Sie das Modal anzeigen, und die 'Eltern'-Ansicht auf die vorherige Ausrichtung zurücksetzen konnten, wenn Sie mondän sein wollten es!
Natalia
3
Könnte dies dazu führen, dass Apple Ihre App ablehnt? Orientierung ist eine schreibgeschützte Eigenschaft, und Sie bearbeiten den Wert. Ich würde denken, Apple würde dies missbilligen.
Puls4life
1
arbeitete für mich unter iOS 14, Swift 5.3, nur durch Überschreiben von shouldAutorotate.
Quarac
59

Swift 4

override func viewDidLoad() {
    super.viewDidLoad()
    let value = UIInterfaceOrientation.landscapeLeft.rawValue
    UIDevice.current.setValue(value, forKey: "orientation")
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .landscapeLeft
}

override var shouldAutorotate: Bool {
    return true
}

Wenn Ihre Ansicht in einen Navigationscontroller eingebettet ist, funktioniert das oben genannte allein nicht. Sie müssen nach der Klassendefinition mit der folgenden Erweiterung kaskadieren.

extension UINavigationController {

override open var shouldAutorotate: Bool {
    get {
        if let visibleVC = visibleViewController {
            return visibleVC.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation{
    get {
        if let visibleVC = visibleViewController {
            return visibleVC.preferredInterfaceOrientationForPresentation
        }
        return super.preferredInterfaceOrientationForPresentation
    }
}

override open var supportedInterfaceOrientations: UIInterfaceOrientationMask{
    get {
        if let visibleVC = visibleViewController {
            return visibleVC.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }
}}


Swift 3

override func viewDidLoad() {
    super.viewDidLoad()
    let value = UIInterfaceOrientation.landscapeLeft.rawValue
    UIDevice.current.setValue(value, forKey: "orientation")
}

private func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.landscapeLeft
}

private func shouldAutorotate() -> Bool {
    return true
}
Manee ios
quelle
3
Dieser Code funktioniert nicht unter iOS 12. Die App stürzt ab und zeigt den Fehler "Unterstützte Ausrichtungen haben keine gemeinsame Ausrichtung mit der Anwendung und [PlayerViewController shouldAutorotate] gibt JA zurück"
Mayur Rathod
@ MayurRathod hast du das Update für deinen Absturz gefunden?
Shirish
@ Shirish Ja, ich habe Orientierungsänderungscode in der Delegatendatei implementiert
Mayur Rathod
@ MayurRathod Wenn Sie Zeit haben, können Sie bitte Ihre Antwort posten
Mark
Die Lösung funktioniert gut für das iPhone, aber auf dem iPad ist der präsentierende Controller und damit die gesamte App auf Landschaft ausgerichtet. Irgendeine Idee, wo kann ich mich irren?
user550088
29

Swift 4 , getestet in iOS 11

Sie können die Ausrichtung unter projectTarget -> General -> DeploymentInfo (Geräteorientierung) -> Portrait angeben (Landscapeleft und Landscaperight sind optional).

AppDelegate

    var myOrientation: UIInterfaceOrientationMask = .portrait
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return myOrientation
    }

LandScpaeViewController

override func viewDidLoad() {
        super.viewDidLoad()
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.myOrientation = .landscape
}

OnDismissButtonTap

let appDelegate = UIApplication.shared.delegate as! AppDelegate
 appDelegate.myOrientation = .portrait

Das ist es. :) :)

Zeesha
quelle
2
unterstütztInterfaceOrientationsFor wird nur aufgerufen, wenn das Gerät einmal gedreht wird.
Naga Mallesh Maddali
Das habe ich gesucht, danke! Für alle, die sich über den Unterschied wundern, wird die neue Ansicht in der Rotation ohne Animation angezeigt. Wobei als Einstellung der Ausrichtung auf UIDevice eine Standardrotationsanimation hinzugefügt wird.
PostCodeism
21

Verwenden von Swift 2.2

Versuchen:

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

Gefolgt von:

UIViewController.attemptRotationToDeviceOrientation()

Aus Apples UIViewController-Klassenreferenz:

Einige Ansichts-Controller möchten möglicherweise app-spezifische Bedingungen verwenden, um zu bestimmen, welche Schnittstellenausrichtungen unterstützt werden. Wenn Ihr View Controller dies tut und diese Bedingungen sich ändern, sollte Ihre App diese Klassenmethode aufrufen. Das System versucht sofort, sich in die neue Ausrichtung zu drehen.

Überschreiben Sie dann, wie andere vorgeschlagen haben, die folgenden Methoden entsprechend:

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

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

Ich hatte ein ähnliches Problem mit einer Signaturansicht und dies löste es für mich.

Aidan Malone
quelle
1
Vielen Dank für diese Antwort. Dieser Kommentar> UIViewController.attemptRotationToDeviceOrientation()ist sehr wichtig, da der Controller manchmal nicht weiß, ob die Drehung durchgeführt werden soll oder nicht. Dies weist es jedoch an, die Drehung entsprechend durchzuführen.
Ramandeep Singh Gosal
17

Für mich waren die besten Ergebnisse die Kombination von Zeeshas Antwort und der Antwort von sazz.

Fügen Sie AppDelegate.swift die folgenden Zeilen hinzu:

var orientationLock = UIInterfaceOrientationMask.portrait
var myOrientation: UIInterfaceOrientationMask = .portrait
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return myOrientation
}  

Fügen Sie Ihrer View Controller-Klasse die folgende Zeile hinzu:

let appDel = UIApplication.shared.delegate as! AppDelegate

Fügen Sie Ihrem View Controller die folgenden Zeilen hinzu viewDidLoad():

appDel.myOrientation = .landscape
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")

(optional) Fügen Sie diese Zeile zu Ihrer Entlassungsfunktion hinzu:

appDel.myOrientation = .portrait
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")

Mit diesen Codezeilen wird die Standardausrichtung auf Hochformat festgelegt, beim Laden des Ansichts-Controllers im Querformat gedreht und nach dem Schließen des Ansichts-Controllers wieder auf Hochformat zurückgesetzt.

Microbob
quelle
3
Dies funktioniert auch für mich, da in meinem Projekt -> Bereitstellungsinformationen nur der Porträtmodus ausgewählt ist. Danke
Dasoga
1
Ich habe im Laufe der Jahre viele Methoden ausprobiert. Dies ist bei weitem die einfachste Lösung, keine Iteration über alle gestapelten Controller usw.
Ich
9

Fügen Sie in AppDelegate Folgendes hinzu:

//Orientation Variables
var myOrientation: UIInterfaceOrientationMask = .portrait

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

Fügen Sie dies in viewController hinzu, um die Ausrichtung zu ändern:

override func viewDidLoad() {
        super.viewDidLoad()
        self.rotateToLandsScapeDevice()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.rotateToPotraitScapeDevice()
    }

    func rotateToLandsScapeDevice(){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.myOrientation = .landscapeLeft
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
        UIView.setAnimationsEnabled(true)
    }

    func rotateToPotraitScapeDevice(){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.myOrientation = .portrait
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
        UIView.setAnimationsEnabled(true)
    }
Elangovan
quelle
1
Arbeitete auch nach zweieinhalb Jahren später wie ein Zauber. Vielen Dank.
Onur Şahindur
Perfekte Lösung !!
nitin.agam
Hat jemand einen Fehler mit dieser Lösung? Wenn ich im Querformat drehe, wähle ich mit dem App Task Manager eine andere App auf meinem Gerät aus, navigiere zurück zu meiner App und klicke dann zurück. Die Orientierung bleibt im Querformat.
Grantespo
7

Ich musste einen Controller in die Hochformatausrichtung zwingen. Das Hinzufügen hat bei mir funktioniert.

Swift 4 mit iOS 11

override var   supportedInterfaceOrientations : UIInterfaceOrientationMask{

    return  .portrait

}
Rob Schlackman
quelle
4

Überschreiben (in ViewController):

override public var shouldAutorotate: Bool {
    return false
} 

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .landscapeRight
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .landscapeRight
}

Hinweis für ios 13. Ab ios 13 verfügt VC über eine andere modale Ansicht modalPresentationStyleals .automaticund das Gerät anstelle der Vollbild-VC. Zur Behebung dieses muss man Satz modalPresentationStylezu .fullScreen. Beispiel:

let viewController = YourViewController()
viewController.modalPresentationStyle = .fullScreen
Jaroslaw Havrylowitsch
quelle
viewController.modalPresentationStyle = .fullScreen hat mir geholfen. Vielen Dank!
anoo_radha
2

Funktioniert in Swift 2.2

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if self.window?.rootViewController?.presentedViewController is SignatureViewController {

        let secondController = self.window!.rootViewController!.presentedViewController as! SignatureViewController

        if secondController.isPresented {

            return UIInterfaceOrientationMask.LandscapeLeft;

        } else {

            return UIInterfaceOrientationMask.Portrait;
        }

    } else {

        return UIInterfaceOrientationMask.Portrait;
    }
}
idris yıldız
quelle
Geht der obige Code in AppDelegate oder nur in den ViewController, den Sie zum Hochformat erzwingen möchten?
Natalia
2

Swift 3. Dadurch wird die Ausrichtung jedes Mal gesperrt, wenn der Benutzer die App erneut öffnet.

class MyViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()

        // Receive notification when app is brought to foreground
        NotificationCenter.default.addObserver(self, selector: #selector(self.onDidBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
    }

    // Handle notification
    func onDidBecomeActive() {
        setOrientationLandscape()
    }

    // Change orientation to landscape
    private func setOrientationLandscape() {
        if !UIDevice.current.orientation.isLandscape {
            let value = UIInterfaceOrientation.landscapeLeft.rawValue
            UIDevice.current.setValue(value, forKey:"orientation")
            UIViewController.attemptRotationToDeviceOrientation()
        }
    }

    // Only allow landscape left
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.landscapeLeft
    }

    /*
    // Allow rotation - this seems unnecessary
    private func shouldAutoRotate() -> Bool {
        return true
    }
    */
    ...
}
Greg T.
quelle
2

Swift 4

Der Versuch, die Orientierung beizubehalten, hat nichts geklappt, aber das für mich:

...        
override func viewDidLoad() {
       super.viewDidLoad()
       forcelandscapeRight()
       let notificationCenter = NotificationCenter.default
       notificationCenter.addObserver(self, selector: #selector(forcelandscapeRight), name: Notification.Name.UIDeviceOrientationDidChange, object: nil)
    }

    @objc func forcelandscapeRight() {
        let value = UIInterfaceOrientation.landscapeRight.rawValue
        UIDevice.current.setValue(value, forKey: "orientation")
    }
....
Daxito
quelle
2

Rufen Sie in ViewController in viewDidLoad Method die folgende Funktion auf

func rotateDevice(){
    UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
    UIView.setAnimationsEnabled(true) // while rotating device it will perform the rotation animation
}`

App Delegate File Add Below Function & Variables

//Orientation Variables
var orientationLock = UIInterfaceOrientationMask.portrait
var myOrientation: UIInterfaceOrientationMask = .portrait

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return .landscape }
Mayur Rathod
quelle
0

Meine Lösung ist

gerade unten Codes in AppDelegate hinzugefügt

enum PossibleOrientations {
  case portrait
    case landscape

    func o() -> UIInterfaceOrientationMask {
      switch self {
      case .portrait:
        return .portrait
      case .landscape:
        return .landscapeRight
      }
    }
}
var orientation: UIInterfaceOrientationMask = .portrait

func switchOrientation(to: PossibleOrientations) {
    let keyOrientation = "orientation"

    if to == .portrait && UIDevice.current.orientation.isPortrait {
        return
    } else if to == .landscape && UIDevice.current.orientation.isLandscape {
        return
    }

    switch to {
    case .portrait:
        orientation = .portrait
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: keyOrientation)
    case .landscape:
        orientation = .landscapeRight
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: keyOrientation)
    }
}

Und rufen Sie die folgenden Codes auf, um sie zu ändern

override func viewDidLoad() {
    super.viewDidLoad()

    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        appDelegate.switchOrientation(to: .landscape)
    }
}

oder wie unten

@IBAction func actBack() {
    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        appDelegate.switchOrientation(to: .portrait)
    }
    self.navigationController?.popViewController(animated: true)
}
Utku
quelle
0
// below code put in view controller
// you can change landscapeLeft or portrait

override func viewWillAppear(_ animated: Bool) {
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
    }

override var shouldAutorotate: Bool {
        return true
    }
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .landscapeRight
    }
    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .landscapeRight
    }
Muthuraj M.
quelle
0

Ich hatte in meinem Projekt ein ähnliches Problem. Es wird nur das Porträt unterstützt. Die ViewController-Struktur besteht darin, dass die Navigation einen Controller (ich habe A genannt) und eine lange Bildlaufansicht in einem Controller enthielt. Ich brauche A (Porträt) als Geschenk für B (Querformat rechts).

Am Anfang habe ich die folgende Methode ausprobiert und sie schien zu funktionieren, aber schließlich habe ich einen Fehler darin gefunden.

Swift 5 & iOS12

// In B controller just override three properties

override var shouldAutorotate: Bool {
    return false
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.landscapeRight
}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .landscapeRight
}

Und dann wird etwas seltsam. Wenn Controller B zu Controller A entlassen wird. Die ScrollView in Controller A wurde irgendwann verschoben.

Also habe ich eine andere Methode verwendet, also drehe ich den Bildschirm, wenn viewWillAppear. Sie können den Code dafür unten sehen.

// In controller B
// not need override shouldAutorotate , supportedInterfaceOrientations , preferredInterfaceOrientationForPresentation

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let appDel = UIApplication.shared.delegate as! AppDelegate
    appDel.currentOrientation = .landscapeRight
    UIDevice.current.setValue( UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
    UIViewController.attemptRotationToDeviceOrientation()
}

//in viewWillDisappear rotate to portrait can not fix the bug


override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    let appDel = UIApplication.shared.delegate as! AppDelegate
    appDel.currentOrientation = .portrait
    UIDevice.current.setValue( UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
    UIViewController.attemptRotationToDeviceOrientation() //must call 
    super.dismiss(animated: true, completion: nil)
}
// in AppDelegate
// the info plist is only supported portrait also, No need to change it

var currentOrientation : UIInterfaceOrientationMask = .portrait


func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return self.currentOrientation
}
kkklc
quelle
Können Sie ein Beispiel / eine Demo zum Ändern der Ausrichtung beim Klicken auf die Schaltfläche erstellen?
Chandan Jee
0

Ich habe viele der folgenden Antworten ausprobiert, aber ich fürchte, sie haben nicht funktioniert. Insbesondere, wenn Navigationsleisten und Registerkarten auch in der App implementiert sind. Die Lösung, die für mich funktioniert hat, wurde von Sunny Lee für diesen Beitrag hier bereitgestellt: Sunny Lee, mittlerer Beitrag

Was wiederum ein Update dieses Beitrags ist: Ursprüngliche Lösung

Die einzige Änderung, die ich bei der Implementierung der Post-Lösung vorgenommen habe, war die Änderung des Teils, der auf .allButUpsideDown verweist, auf .landscapeleft

Zenman C.
quelle
0

In Xcode 11 mit Swift 5 habe ich Folgendes implementiert. Dies funktioniert jedoch nur, wenn die Geräteorientierung für das Projektziel nicht alle Orientierungen enthält. Ich habe die Prüfung für Upside Down deaktiviert. Danach funktioniert der folgende Code. Wenn alle Kontrollkästchen aktiviert sind, wird der Code nicht aufgerufen.

class MyController : UINavigationController {

    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .landscape
    }


}
Raymond
quelle
-3
class CustomUIViewController : UIViewController{

    override var   supportedInterfaceOrientations : UIInterfaceOrientationMask{

        return  .landscapeLeft

    }

}


class ViewController: CustomUIViewController {
.
.
.
}
Tal
quelle
Willkommen auf Stack - Überlauf, wie Antwort richtig zu schreiben , überprüft hier .
Rahul Sharma