Como bloquear a orientação de um controlador de visualização para o modo retrato apenas em Swift

95

Pois meu aplicativo tem suporte para todas as orientações. Eu gostaria de bloquear apenas o modo retrato para UIViewController específico.

por exemplo, suponha que foi um aplicativo com guias e quando o SignIn View aparecer modalmente, eu só quero que o SignIn View no modo retrato não importa como o usuário gire o dispositivo ou como a orientação atual do dispositivo será

Thiha Aung
fonte
Isso pode ajudar stackoverflow.com/q/24928057/6521116
Kris Roofe

Respostas:

262

As coisas podem ficar um pouco confusas quando você tem uma hierarquia de visualização complicada, como ter vários controladores de navegação e / ou controladores de visualização de guia.

Essa implementação permite que os controladores de visualização individuais definam quando desejam bloquear as orientações, em vez de depender do App Delegate para localizá-las iterando por meio de subvisualizações.

Swift 3, 4, 5

Em AppDelegate:

/// set orientations you want to be allowed in this property by default
var orientationLock = UIInterfaceOrientationMask.all

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

Em alguma outra estrutura global ou classe auxiliar, criei aqui AppUtility:

struct AppUtility {

    static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
    
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }

    /// OPTIONAL Added method to adjust lock and rotate to the desired orientation
    static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
   
        self.lockOrientation(orientation)
    
        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
        UINavigationController.attemptRotationToDeviceOrientation()
    }

}

Então, no ViewController desejado, você deseja bloquear as orientações:

 override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    AppUtility.lockOrientation(.portrait)
    // Or to rotate and lock
    // AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)
    
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    // Don't forget to reset when view is being removed
    AppUtility.lockOrientation(.all)
}

Se for iPad ou aplicativo universal

Certifique-se de que "Requer tela inteira" esteja marcado em Configurações de destino -> Geral -> Informações de implantação. supportedInterfaceOrientationsFordelegado não será chamado se não estiver marcado. insira a descrição da imagem aqui

bmjohns
fonte
Parece que é controle de código ... deixe-me verificar, parece uma boa resposta.
Thiha Aung
17
Depois de muita pesquisa insana, esta é a única resposta que achei que funciona para mim. Swift 3 - Xcode 8.2.1
Xavier Garcia Rubio
1
@pbm Vários dos aplicativos da empresa, trabalho com orientações de bloqueio em partes específicas do aplicativo, e todos foram aprovados para a app store várias vezes, ao longo de muitos anos. Dito isso, não posso garantir que a Apple não terá problemas com isso no futuro. Mas até agora não houve problemas, e tenho quase certeza de que muitos aplicativos fazem isso de uma forma ou de outra.
bmjohns
2
Se marcar Requires full screen, isso impedirá que o aplicativo fique disponível para Slide Over e Split View. Consulte Adotando aprimoramentos de multitarefa no iPad da Apple. Tenho uma resposta que não requer ativaçãoRequires full screen
John Pang
2
Não está funcionando, o segundo layout do viewController não atualizou sua exibição apenas em retrato.
O iCoder
27

Swift 4

insira a descrição da imagem aqui AppDelegate

var orientationLock = UIInterfaceOrientationMask.all

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return self.orientationLock
}
struct AppUtility {
    static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }

    static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
        self.lockOrientation(orientation)
        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
    }
}

Seu ViewController Adicione a linha seguinte se você precisar apenas da orientação retrato. você tem que aplicar isso a todas as necessidades do ViewController para exibir o modo retrato.

override func viewWillAppear(_ animated: Bool) {
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
    }

e isso fará a orientação da tela para outros Viewcontroller de acordo com a orientação física do dispositivo.

override func viewWillDisappear(_ animated: Bool) {
        AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.all)

    }
Nahid Raihan
fonte
Para o Swift 4, esta é definitivamente a melhor resposta. É exatamente o que eu precisava, pois imita o comportamento do aplicativo de câmera do iOS.
nocdib
@Nahid Substituímos o original func application dentro do delegado do aplicativo por esta funçãofunc application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock ?
Moondra de
Depois de horas ou duas procurando uma solução e algumas tentativas, esta é a solução que funciona perfeitamente. Ele define a orientação da vista, força quando a vista é carregada, desbloqueia quando vai para outra vista, funciona na navegação por abas e o código é simples e limpo. Obrigado @Nahid
Radek Sip
12

Swift 3 e 4

Defina a supportedInterfaceOrientationspropriedade de UIViewControllers específicos como este:

class MyViewController: UIViewController {

    var orientations = UIInterfaceOrientationMask.portrait //or what orientation you want
    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
    get { return self.orientations }
    set { self.orientations = newValue }
    }

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

    //...
}

ATUALIZAR

Esta solução só funciona quando seu nãoviewController está incorporado , porque a orientação é herdada do viewController pai. Nesse caso, você pode criar uma subclasse de e definir essas propriedades nela.UINavigationController
UINavigationViewController

Arash Etemad
fonte
Obrigado. Isso funciona bem para mim porque desejo apenas restringir uma visão específica ao retrato. Nem todo o aplicativo.
user3204765
Tudo que eu preciso é controlar controladores de visualização específicos para bloquear a orientação, independentemente da orientação do dispositivo e isso funcionou muito bem!
Ryan B.
9

Adicione este código para forçar o retrato e bloqueá-lo:

override func viewDidLoad() {
    super.viewDidLoad()

    // Force the device in portrait mode when the view controller gets loaded
    UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation") 
}

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

override func supportedInterfaceOrientations() -> Int {

    // Only allow Portrait
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {

    // Only allow Portrait
    return UIInterfaceOrientation.Portrait
}

Em seu AppDelegate - defina supportedInterfaceOrientationsForWindow para quaisquer orientações que você deseja que todo o aplicativo suporte:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.All
} 
Valentin
fonte
Obrigado Valentin, realmente apreciei sua ajuda.Mas, seu código não funcionou.E eu resolvi agora.Eu também respondi à minha pergunta.
Thiha Aung
7

Esta é uma solução genérica para o seu problema e outros relacionados.

1. Crie a classe auxiliar UIHelper e use os seguintes métodos:

    /**This method returns top view controller in application  */
    class func topViewController() -> UIViewController?
    {
        let helper = UIHelper()
        return helper.topViewControllerWithRootViewController(rootViewController: UIApplication.shared.keyWindow?.rootViewController)
    }

    /**This is a recursive method to select the top View Controller in a app, either with TabBarController or not */
    private func topViewControllerWithRootViewController(rootViewController:UIViewController?) -> UIViewController?
    {
        if(rootViewController != nil)
        {
            // UITabBarController
            if let tabBarController = rootViewController as? UITabBarController,
                let selectedViewController = tabBarController.selectedViewController {
                return self.topViewControllerWithRootViewController(rootViewController: selectedViewController)
            }

            // UINavigationController
            if let navigationController = rootViewController as? UINavigationController ,let visibleViewController = navigationController.visibleViewController {
                return self.topViewControllerWithRootViewController(rootViewController: visibleViewController)
            }

            if ((rootViewController!.presentedViewController) != nil) {
                let presentedViewController = rootViewController!.presentedViewController;
                return self.topViewControllerWithRootViewController(rootViewController: presentedViewController!);
            }else
            {
                return rootViewController
            }
        }

        return nil
    }

2. Crie um Protocolo com o seu comportamento desejado, pois seu caso específico será retrato.

orientação do protocoloIsOnlyPortrait {}

Nota: Se desejar, adicione-o no início da classe UIHelper.

3. Estenda seu controlador de visualização

No seu caso:

class Any_ViewController: UIViewController,orientationIsOnlyPortrait {

   ....

}

4. Na classe de delegado do aplicativo, adicione este método:

 func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        let presentedViewController = UIHelper.topViewController()
        if presentedViewController is orientationIsOnlyPortrait {
            return .portrait
        }
        return .all
    }

Notas Finais:

  • Se você que mais turmas estão no modo retrato, basta estender esse protocolo.
  • Se você deseja outros comportamentos dos controladores de visualização, crie outros protocolos e siga a mesma estrutura.
  • Este exemplo resolve o problema com mudanças de orientação após o envio de controladores de visualização
Ariel Antonio Fundora
fonte
Como esta solução, mas achei as funções UIHelper mais úteis como extensões para UINavigationController.
Michael Long de
5

Um monte de ótimas respostas neste tópico, mas nenhuma correspondeu às minhas necessidades. Eu tenho um aplicativo com guias com controladores de navegação em cada guia e uma visualização precisa ser girada, enquanto as outras precisam ser travadas no modo retrato. O controlador de navegação não estava redimensionando suas subvisualizações corretamente, por algum motivo. Encontrou uma solução (no Swift 3) combinando com esta resposta, e os problemas de layout desapareceram. Crie a estrutura conforme sugerido por @bmjohns:

import UIKit

struct OrientationLock {

    static func lock(to orientation: UIInterfaceOrientationMask) {
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }

    static func lock(to orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) {
        self.lock(to: orientation)
        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
    }
} 

Em seguida, subclasse UITabBarController:

    import UIKit

class TabBarController: UITabBarController, UITabBarControllerDelegate {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.delegate = self
    }

    func tabBarControllerSupportedInterfaceOrientations(_ tabBarController: UITabBarController) -> UIInterfaceOrientationMask {
        if tabBarController.selectedViewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
            return .allButUpsideDown
        } else if let navController = tabBarController.selectedViewController as? UINavigationController, navController.topViewController is MyViewControllerInANavControllerThatShouldRotate {
            return .allButUpsideDown
        } else {
            //Lock view that should not be able to rotate
            return .portrait
        }
    }

    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        if viewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
            OrientationLock.lock(to: .allButUpsideDown)
        } else if let navController = viewController as? UINavigationController, navController.topViewController is MyViewControllerInANavigationControllerThatShouldRotate {
            OrientationLock.lock(to: .allButUpsideDown)
        } else {
            //Lock orientation and rotate to desired orientation
            OrientationLock.lock(to: .portrait, andRotateTo: .portrait)
        }
        return true
    }
}

Não se esqueça de alterar a classe do TabBarController no storyboard para a subclasse recém-criada.

Russdub
fonte
5

Para uma nova versão do Swift, experimente isto

override var shouldAutorotate: Bool {
    return false
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}
Khemmachart Chutapetch
fonte
É exatamente o que eu precisava! Para o controlador do iPad, todas as opções de orientação são válidas e para o controlador do iPhone apenas no modo retrato, escrevendo nele apenas estas três substituições - Perfeito.
VYT
4

Esta é uma maneira simples que funciona para mim com o Swift 4.2 (iOS 12.2), coloque em um UIViewControllerpara o qual deseja desativar o shouldAutorotate:

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

A .portraitparte informa em qual orientação permanecer, você pode alterar isso como quiser. As opções são: .portrait, .all, .allButUpsideDown, .landscape, .landscapeLeft, .landscapeRight, .portraitUpsideDown.

GregT
fonte
2

Para definir a orientação Paisagem para todas as visualizações do seu aplicativo e permitir apenas uma visualização para Todas as orientações (para poder adicionar o rolo da câmera, por exemplo):

Em AppDelegate.swift:

var adaptOrientation = false

In: didFinishLaunchingWithOptions

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

Em outro lugar em AppDelegate.swift:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    return checkOrientation(self.window?.rootViewController)
}

func checkOrientation(viewController:UIViewController?)-> Int{
    if (adaptOrientation == false){
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }else {
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }
}

func adaptOrientationAction(notification: NSNotification){
    if adaptOrientation == false {
        adaptOrientation = true
    }else {
        adaptOrientation = false
    }
}

Então, na visualização que segue para aquela que você deseja, poderá ter Todas as orientações:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if (segue.identifier == "YOURSEGUE") {
        NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
    }
}

override func viewWillAppear(animated: Bool) {
    if adaptOrientation == true {
        NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
    }
}

A última coisa é marcar a orientação do dispositivo: - Retrato - Paisagem à esquerda - Paisagem à direita

Fluxo de iOS
fonte
2

Crie uma nova extensão com

import UIKit

extension UINavigationController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

extension UITabBarController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}
Felipe kimio
fonte
1

bmjohns -> Você é meu salvador de vida. Essa é a única solução de trabalho (com a estrutura AppUtility)

Eu criei esta classe:

class Helper{
    struct AppUtility {

        static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {

            if let delegate = UIApplication.shared.delegate as? AppDelegate {
                delegate.orientationLock = orientation
            }
        }

        /// OPTIONAL Added method to adjust lock and rotate to the desired orientation
        static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {

            self.lockOrientation(orientation)

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

    }
}

e seguiu suas instruções, e tudo funciona perfeitamente para Swift 3 -> xcode versão 8.2.1

Stjepan
fonte
1

A partir do iOS 10 e 11, o iPad suporta Slide Over e Split View. Para habilitar um aplicativo em Slide Over e Split View, Requires full screen deve estar desmarcado. Isso significa que a resposta aceita não pode ser usada se o aplicativo quiser suportar Slide Over e Split View. Veja mais de Adoção de melhorias multitarefa no iPad da Apple aqui .

Eu tenho uma solução que permite (1) desmarcar Requires full screen, (2) apenas uma função a ser implementada appDelegate(especialmente se você não quiser / não pode modificar os controladores de exibição de destino) e (3) evitar chamadas recursivas. Não há necessidade de classes auxiliares nem extensões.

appDelegate.swift (Swift 4)

func application(_ application: UIApplication,
                 supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    // Search for the visible view controller
    var vc = window?.rootViewController
    // Dig through tab bar and navigation, regardless their order 
    while (vc is UITabBarController) || (vc is UINavigationController) {
        if let c = vc as? UINavigationController {
            vc = c.topViewController
        } else if let c = vc as? UITabBarController {
            vc = c.selectedViewController
        }
    }
    // Look for model view controller
    while (vc?.presentedViewController) != nil {
        vc = vc!.presentedViewController
    }
    print("vc = " + (vc != nil ? String(describing: type(of: vc!)) : "nil"))
    // Final check if it's our target class.  Also make sure it isn't exiting.
    // Otherwise, system will mistakenly rotate the presentingViewController.
    if (vc is TargetViewController) && !(vc!.isBeingDismissed) {
        return [.portrait]
    }
    return [.all]
}

Editar

@bmjohns apontou que esta função não é chamada no iPad. Verifiquei e sim não foi chamado. Então, fiz mais alguns testes e descobri alguns fatos:

  1. Desmarquei Requires full screenporque desejo habilitar Slide Over e Slide View no iPad. Que requer o aplicativo para suportar todos os 4 orientação para iPad, em Info.plist: Supported interface orientations (iPad).

Meu aplicativo funciona da mesma maneira que o Facebook: no iPhone, na maioria das vezes ele está bloqueado para retrato. Ao visualizar a imagem em tela cheia, permite aos usuários girar a paisagem para uma melhor visualização. No iPad, os usuários podem girar para qualquer orientação em qualquer controlador de visualização. Portanto, o aplicativo fica bem quando o iPad está na Smart Cover (paisagem à esquerda).

  1. Para que o iPad faça a chamada application(_:supportedInterfaceOrientationsFor), em Info.plist, mantenha apenas o retrato para o iPad. O aplicativo perderá a capacidade de Slide Over + Split View. Mas você pode bloquear ou desbloquear a orientação para qualquer controlador de visualização, em apenas um lugar e sem necessidade de modificar a classe ViewController.

  2. Finalmente, esta função é chamada no ciclo de vida do controlador de visualização, quando a visualização é exibida / removida. Se seu aplicativo precisar bloquear / desbloquear / alterar a orientação em outro momento, pode não funcionar

John Pang
fonte
Está funcionando para o iPhone? Quero mostrar um dos meus viewController apenas em paisagem.
O iCoder
Sim. trabalhar para iPhone. Quero um dos meus controladores de visualização em retrato e paisagem, e retornar ao retrato após descartá-lo.
John Pang,
1

Solução real testada para isso . No meu exemplo, preciso que todo o meu aplicativo esteja no modo retrato, mas apenas a orientação de uma tela deve estar no modo paisagem. Faça uma orientação Retrato para o aplicativo, marcando apenas o modo retrato

Codifique em AppDelegate conforme as respostas acima descritas.

var orientationLock = UIInterfaceOrientationMask.all

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask 
{
  return self.orientationLock
}
struct AppUtility {  

static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
    if let delegate = UIApplication.shared.delegate as? AppDelegate {
        delegate.orientationLock = orientation
    }
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)     
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}  
}

Em seguida, anote este código antes que seu viewcontroller de orientação horizontal seja apresentado / push.

override func viewWillAppear(_ animated: Bool) {  
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}  

Em seguida, escreva este código no viewcontroller real (para visualização em paisagem)

override func viewWillAppear(_ animated: Bool) {  
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscape, andRotateTo: UIInterfaceOrientation.landscape)
}  
Gurpreet Singh
fonte
1

Experimentei um pouco e consegui encontrar uma solução limpa para este problema. A abordagem é baseada na marcação da visualização via view-> tag

No ViewController de destino, apenas atribua a tag à visualização raiz como no exemplo de código a seguir:

class MyViewController: BaseViewController {

  // declare unique view tag identifier
  static let ViewTag = 2105981;

  override func viewDidLoad()
  {
    super.viewDidLoad();
    // assign the value to the current root view
    self.view.tag = MyViewController.ViewTag;
  }

E, finalmente, no AppDelegate.swift, verifique se a visualização exibida atualmente é a que marcamos:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
    if (window?.viewWithTag(DesignerController.ViewTag)) != nil {
        return .portrait;
    }
    return .all;
}

Essa abordagem foi testada com meu simulador e parece que funciona bem.

Nota: a visualização marcada também será encontrada se o MVC atual for sobreposto a algum ViewController filho na pilha de navegação.

Vlada
fonte
0

Obrigado à resposta de @bmjohn acima. Aqui está uma versão Xamarin / C # funcional do código dessa resposta, para economizar o tempo da transcrição de outros:

AppDelegate.cs

 public UIInterfaceOrientationMask OrientationLock = UIInterfaceOrientationMask.All;
 public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
 {
     return this.OrientationLock;
 }

Classe Static OrientationUtility.cs:

public static class OrientationUtility
{
    public static void LockOrientation(UIInterfaceOrientationMask orientation)
    {
        var appdelegate = (AppDelegate) UIApplication.SharedApplication.Delegate;
        if(appdelegate != null)
        {
            appdelegate.OrientationLock = orientation;
        }
    }

    public static void LockOrientation(UIInterfaceOrientationMask orientation, UIInterfaceOrientation RotateToOrientation)
    {
        LockOrientation(orientation);

        UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)RotateToOrientation), new NSString("orientation"));
    }
}

Ver controlador:

    public override void ViewDidAppear(bool animated)
    {
       base.ViewWillAppear(animated);
       OrientationUtility.LockOrientation(UIInterfaceOrientationMask.Portrait, UIInterfaceOrientation.Portrait);
    }

    public override void ViewWillDisappear(bool animated)
    {
        base.ViewWillDisappear(animated);
        OrientationUtility.LockOrientation(UIInterfaceOrientationMask.All);
    }
ccs_dev
fonte
Eu não entendo como essa resposta é relevante? Essa pessoa pediu rapidamente e você deu em Xamarin.
Mihir Oza
0

Melhor solução para bloquear e alterar a orientação em retrato e paisagem:

Veja este vídeo no YouTube:

https://m.youtube.com/watch?v=4vRrHdBowyo

Este tutorial é melhor e simples.

ou use o código abaixo:

Veja esta foto

// 1- no segundo viewcontroller definimos landscapeleft e no primeiro viewcontroller definimos portrat:

// 2- se você usar NavigationController, você deve adicionar a extensão

import UIKit

class SecondViewController: UIViewController {


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

    override open var shouldAutorotate: Bool {
        return false
    }

    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .landscapeLeft
    }

    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .landscapeLeft
    }
    
    

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

//write The rest of your code in here


}

//if you use NavigationController, you should add this extension

extension UINavigationController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
    
    }
}
OliaPh
fonte