Как заблокировать ориентацию одного контроллера представления в портретном режиме только в Swift

102

Поскольку мое приложение поддерживает любую ориентацию. Я хотел бы заблокировать только портретный режим для определенного UIViewController.

например, предположим, что это было приложение с вкладками, и когда представление входа в систему отображается модально, я хочу, чтобы этот вид входа был только в портретном режиме, независимо от того, как пользователь поворачивает устройство или как будет текущая ориентация устройства

Тиха Аунг
источник
Это может помочь stackoverflow.com/q/24928057/6521116
Крис Руф

Ответы:

270

Все может стать довольно запутанным, когда у вас сложная иерархия представлений, например, наличие нескольких контроллеров навигации и / или контроллеров представления вкладок.

Эта реализация помещает его в отдельные контроллеры представления, чтобы установить, когда они хотели бы заблокировать ориентацию, вместо того, чтобы полагаться на делегата приложения, чтобы найти их путем итерации по вложенным представлениям.

Свифт 3, 4, 5

В 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
}

В какой-то другой глобальной структуре или вспомогательном классе я создал 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()
    }

}

Затем в желаемом ViewController вы хотите заблокировать ориентацию:

 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)
}

Если iPad или универсальное приложение

Убедитесь, что "Требуется полноэкранный режим" отмечен в Target Settings -> General -> Deployment Info. supportedInterfaceOrientationsForделегат не будет вызван, если он не отмечен. введите описание изображения здесь

bmjohns
источник
Похоже, это контроль кода ... позвольте мне проверить, похоже, хороший ответ.
Thiha Aung
18
После множества безумных исследований, это единственный ответ, который мне подходит. Swift 3 - Xcode 8.2.1
Ксавьер Гарсия Рубио
1
@pbm Некоторые приложения в компании, в которых я работаю, блокируют ориентацию в определенных частях приложения, и все они были одобрены в магазине приложений несколько раз на протяжении многих лет. Тем не менее, я не могу гарантировать, что у Apple не возникнет проблем с этим в будущем. Но пока никаких проблем, и я почти уверен, что многие приложения делают это в той или иной форме.
bmjohns
2
Если этот флажок установлен Requires full screen, приложение будет недоступно для скользящего и разделенного просмотра. См. Раздел « Внедрение улучшений многозадачности на iPad от Apple». У меня ответ не требует включенияRequires full screen
Джон Панг
2
Он не работает, второй макет viewController не обновляет отображение только в портретной ориентации.
The iCoder 05
28

Swift 4

введите описание изображения здесь 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")
    }
}

Ваш ViewController Добавьте следующую строку, если вам нужна только портретная ориентация. вы должны применить это ко всем ViewController, который должен отображать портретный режим.

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

и это сделает ориентацию экрана для других Viewcontroller в соответствии с физической ориентацией устройства.

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

    }
Нахид Райхан
источник
Для Swift 4 это определенно лучший ответ. Это именно то, что мне нужно, поскольку оно имитирует поведение приложения камеры iOS.
nocdib
@Nahid Заменим ли мы оригинал func application в делегате приложения этой функциейfunc application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock ?
Moondra
После часа или двух поисков решения и нескольких попыток это идеальное рабочее решение. Он устанавливает ориентацию представления, заставляет его при загрузке представления, разблокировать при переходе к другому представлению, он работает в навигации по вкладкам, а код прост и понятен. Спасибо @Nahid
Радек Сип
13

Swift 3 и 4

Установите supportedInterfaceOrientationsсвойство определенных UIViewControllers следующим образом:

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()
    }

    //...
}

ОБНОВИТЬ

Это решение работает только тогда , когда ваш viewControllerбудет не встроен в UINavigationController, поскольку ориентация наследуется от родительского ViewController.
В этом случае вы можете создать подкласс UINavigationViewControllerи установить для него эти свойства.

Араш Этемад
источник
Спасибо. Это хорошо работает для меня, потому что я хочу ограничить определенный вид только портретом. Не все приложение.
user3204765
Все, что мне нужно, это управлять определенными контроллерами представления, чтобы заблокировать ориентацию независимо от ориентации устройства, и это отлично сработало!
Райан Б.
9

Добавьте этот код, чтобы заставить портрет и заблокировать его:

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
}

В вашем AppDelegate установите для supportedInterfaceOrientationsForWindow любую ориентацию, которую вы хотите, чтобы все приложение поддерживало:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.All
} 
Валентин
источник
Спасибо Валентин, я очень признателен за вашу помощь, но у вас не получилось кодить. И я решил сейчас. Я тоже ответил на свой вопрос.
Тиха Аунг
8

Это общее решение вашей и других проблем.

1. Создайте дополнительный класс UIHelper и включите следующие методы:

    /**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. Создайте протокол с вашим желанием поведения, для вашего конкретного случая будет портрет.

ориентация протоколаIsOnlyPortrait {}

Примечание: если хотите, добавьте его в начало класса UIHelper.

3. Расширьте свой View Controller

В твоем случае:

class Any_ViewController: UIViewController,orientationIsOnlyPortrait {

   ....

}

4. В классе делегата приложения добавьте этот метод:

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

Заключительные примечания:

  • Если у вас еще один класс в портретном режиме, просто расширьте этот протокол.
  • Если вы хотите, чтобы контроллеры представлений использовали поведение других, создайте другие протоколы и следуйте той же структуре.
  • В этом примере решается проблема с изменением ориентации после нажатия контроллеров представления.
Ариэль Антонио Фундора
источник
Как и это решение, но я считаю, что функции UIHelper более полезны как расширения для UINavigationController.
Майкл Лонг
7

Для новой версии Swift попробуйте это

override var shouldAutorotate: Bool {
    return false
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}
Хеммачарт Чутапетч
источник
Это именно то, что мне было нужно! Для контроллера iPad все варианты ориентации действительны, а для контроллера iPhone - только портретный режим, записав в нем только эти три переопределения - Perfect.
VYT
5

Куча отличных ответов в этой теме, но ни один из них не соответствовал моим потребностям. У меня есть приложение с вкладками с контроллерами навигации на каждой вкладке, и одно представление необходимо вращать, а другие необходимо заблокировать в портретной ориентации. Контроллер навигации по какой-то причине не менял размер своих подвидов должным образом. Нашел решение (в Swift 3), объединив с этим ответом, и проблемы с макетом исчезли. Создайте структуру, как предлагает @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")
    }
} 

Затем подкласс 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
    }
}

Не забудьте изменить класс TabBarController в раскадровке на только что созданный подкласс.

руссдуб
источник
4

Вот простой способ, который у меня работает со Swift 4.2 (iOS 12.2), поместите его в, UIViewControllerдля которого вы хотите отключить shouldAutorotate:

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

.portraitЧасть рассказывает , в которой ориентация (s) , чтобы остаться, вы можете изменить это , как вам нравится. Варианты: .portrait, .all, .allButUpsideDown, .landscape, .landscapeLeft, .landscapeRight, .portraitUpsideDown.

GregT
источник
2

Чтобы установить альбомную ориентацию для всех представлений вашего приложения и разрешить только одно представление для всех ориентаций (например, чтобы иметь возможность добавить камеру):

В AppDelegate.swift:

var adaptOrientation = false

В: didFinishLaunchingWithOptions

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

В другом месте в 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
    }
}

Затем в представлении, которое переходит к тому, которое вы хотите иметь для всех ориентаций:

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)
    }
}

Последнее, что нужно сделать, это отметить ориентацию устройства: - Книжная - Альбомная слева - Альбомная справа

iOS Flow
источник
2

Создать новое расширение с

import UIKit

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

extension UITabBarController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}
Фелипе Кимио
источник
1

bmjohns -> Ты спаситель моей жизни. Это единственное рабочее решение (со структурой AppUtility)

Я создал этот класс:

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")
        }

    }
}

и следовал вашим инструкциям, и все отлично работает для Swift 3 -> xcode версии 8.2.1

Степан
источник
1

Начиная с iOS 10 и 11 iPad поддерживает Slide Over и Split View. Чтобы включить приложение в режиме Slide Over и Split View, Requires full screen необходимо снять флажок. Это означает, что принятый ответ нельзя использовать, если приложение хочет поддерживать Slide Over и Split View. Дополнительные сведения об улучшении многозадачности Apple на iPad можно найти здесь .

У меня есть решение, которое позволяет (1) снять отметку Requires full screen, (2) реализовать только одну функцию appDelegate(особенно если вы не хотите / не можете изменять целевые контроллеры представления) и (3) избегать рекурсивных вызовов. Нет необходимости во вспомогательном классе или расширениях.

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]
}

редактировать

@bmjohns указал, что эта функция не вызывается на iPad. Я проверил, и да, это не называлось. Итак, я провел еще немного тестов и выяснил некоторые факты:

  1. Я снял флажок, Requires full screenпотому что хочу включить на iPad режим «Скольжение» и «Просмотр слайдов». Это требует приложение , чтобы поддержать все 4 ориентации для IPad, в Info.plist: Supported interface orientations (iPad).

Мое приложение работает так же, как Facebook: на iPhone большую часть времени оно заблокировано в портретной ориентации. При просмотре изображения в полноэкранном режиме пользователи могут поворачивать альбомную ориентацию для лучшего просмотра. На iPad пользователи могут поворачивать в любую ориентацию в любых контроллерах представления. Итак, приложение хорошо выглядит, когда iPad установлен на Smart Cover (альбомная ориентация слева).

  1. Чтобы с iPad звонить application(_:supportedInterfaceOrientationsFor), в Info.plist оставьте только вертикальную ориентацию для iPad. Приложение потеряет возможность скольжения и разделения просмотра. Но вы можете заблокировать или разблокировать ориентацию для любого контроллера представления всего в одном месте и не нужно изменять класс ViewController.

  2. Наконец, эта функция вызывается в жизненном цикле контроллера представления, когда представление отображается / удаляется. Если вашему приложению нужно заблокировать / разблокировать / изменить ориентацию в другое время, оно может не работать

Джон Пэнг
источник
На айфоне работает? Я хочу показать один из моих viewController только в альбомной ориентации.
The iCoder
Да. работать на iPhone. Я хочу, чтобы один из моих контроллеров представления был как в портретной, так и в альбомной ориентации, и вернулся к портретному режиму после его отклонения.
Джон Панг
1

Фактическое протестированное решение для этого. В моем примере мне нужно, чтобы все мое приложение было в портретном режиме, но только одна ориентация экрана должна быть в ландшафтном режиме. Сделайте книжную ориентацию для приложения, отметив только портретный режим

Код в 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")
}  
}

Затем запишите этот код до того, как ваш контроллер просмотра с альбомной ориентацией будет представлен / push.

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

Затем запишите этот код в реальном контроллере просмотра (для ландшафтного просмотра)

override func viewWillAppear(_ animated: Bool) {  
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscape, andRotateTo: UIInterfaceOrientation.landscape)
}  
Гурприт Сингх
источник
0

Благодаря ответу @bmjohn выше. Вот рабочая версия Xamarin / C # этого кода ответа, чтобы сэкономить время транскрипции другим:

AppDelegate.cs

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

Статический класс 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"));
    }
}

Просмотр контроллера:

    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
источник
Я не понимаю, насколько этот ответ актуален? Этот человек быстро спросил, и вы дали в Xamarin.
Михир Оза,
0

Я немного поэкспериментировал и мне удалось найти чистое решение этой проблемы. Подход основан на тегировании представления с помощью тега view->.

В целевом ViewController просто назначьте тег корневому представлению, как в следующем примере кода:

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;
  }

И, наконец, в AppDelegate.swift проверьте, является ли текущее отображаемое представление тем, которое мы пометили:

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

Этот подход был протестирован на моем симуляторе и, кажется, работает нормально.

Примечание: отмеченное представление также будет найдено, если текущий MVC перекрывается некоторым дочерним ViewController в стеке навигации.

Влада
источник
0

Лучшее решение для блокировки и изменения ориентации в портретной и альбомной ориентации:

Посмотрите это видео на YouTube:

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

Этот учебник самый лучший и простой.

или используйте код ниже:

Смотрите эту картинку

// 1- во втором контроллере просмотра мы устанавливаем ландшафт слева, а в первом контроллере просмотра устанавливаем portrat:

// 2- если вы используете NavigationController, вы должны добавить расширение

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
    
    }
}
ОляФ
источник