Вращение только в одном ViewController

Я пытаюсь повернуть один вид, в то время как все остальные виды (5) прикреплены к портрету. Причина в том, что в этом представлении я хочу, чтобы пользователь просматривал фотографии, которые он сохранил раньше. Я думаю, это возможно, но пока я не мог понять, как это достичь. Может ли кто-нибудь помочь или дать мне подсказку? Я программирую, что в Swift работает на iOS8

Ответ 1

Это для Swift 3 и Swift 4. Вы можете использовать следующий код в своем AppDelegate.swift:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    guard let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
     (rootViewController.responds(to: Selector(("canRotate")))) else{
        // Only allow portrait (standard behaviour)
        return .portrait;
    }
    // Unlock landscape view orientations for this view controller
    return .allButUpsideDown;
}

private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
    guard rootViewController != nil else { return nil }

    guard !(rootViewController.isKind(of: (UITabBarController).self)) else{
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
    }
    guard !(rootViewController.isKind(of:(UINavigationController).self)) else{
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
    }
    guard !(rootViewController.presentedViewController != nil) else{
        return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
    }
    return rootViewController
}

вы можете узнать больше в исходном посте: http://www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in-ios-slash -swift/

Ответ 2

Я бы рекомендовал использовать supportedInterfaceOrientationsForWindow в вашем appDelegate, чтобы обеспечить вращение только в том, что конкретный вид контроллера, напр:

Свифт 4/Свифт 5

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

    // Make sure the root controller has been set
    // (won't initially be set when the app is launched)
    if let navigationController = self.window?.rootViewController as? UINavigationController {

        // If the visible view controller is the
        // view controller you'd like to rotate, allow
        // that window to support all orientations
        if navigationController.visibleViewController is SpecificViewController {
            return UIInterfaceOrientationMask.all
        } 

        // Else only allow the window to support portrait orientation
        else {
            return UIInterfaceOrientationMask.portrait
        }
    }

    // If the root view controller hasn't been set yet, just
    // return anything
    return UIInterfaceOrientationMask.portrait
}

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


Свифт 3

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {

    // Make sure the root controller has been set
    // (won't initially be set when the app is launched)
    if let navigationController = self.window?.rootViewController as? UINavigationController {

        // If the visible view controller is the
        // view controller you'd like to rotate, allow
        // that window to support all orientations
        if navigationController.visibleViewController is SpecificViewController  {
            return Int(UIInterfaceOrientationMask.All.rawValue)
        }

        // Else only allow the window to support portrait orientation
        else {
            return Int(UIInterfaceOrientationMask.Portrait.rawValue)
        }
    }

    // If the root view controller hasn't been set yet, just
    // return anything
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

Ответ 3

Вы также можете сделать это в соответствии с протоколом. Просто создайте протокол

protocol CanRotate {

}

Добавьте те же 2 метода в AppDelegate более "осторожным" способом

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if topViewController(in: window?.rootViewController) is CanRotate {
        return .allButUpsideDown
    } else {
        return .portrait
    }
}


func topViewController(in rootViewController: UIViewController?) -> UIViewController? {
    guard let rootViewController = rootViewController else {
        return nil
    }

    if let tabBarController = rootViewController as? UITabBarController {
        return topViewController(in: tabBarController.selectedViewController)
    } else if let navigationController = rootViewController as? UINavigationController {
        return topViewController(in: navigationController.visibleViewController)
    } else if let presentedViewController = rootViewController.presentedViewController {
        return topViewController(in: presentedViewController)
    }
    return rootViewController
}

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

class ViewController: UIViewController, CanRotate {}

Если вам нужна какая-то конкретная комбинация, вы можете добавить в протокол переменную, чтобы переопределить

protocol CanRotate {
    var supportedInterfaceOrientations: UIInterfaceOrientationMask
}

Ответ 4

Используйте метод shouldAutorotate и метод supportedInterfaceOrientations в ViewController, который вы хотите отображать в ландшафтном и портретном режимах:

Этот метод должен переопределить настройки раскадровки.

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

override func supportedInterfaceOrientations() -> Int {
    return UIInterfaceOrientation.Portrait.rawValue | UIInterfaceOrientation.LandscapeLeft.rawValue | UIInterfaceOrientation.LandscapeRight.rawValue
}

Ответ 5

Я просто столкнулся с очень похожей проблемой, когда хотел представить видеоплеер в портретном и ландшафтном режимах, тогда как остальная часть приложения - только портрет. Моя основная проблема заключалась в том, что когда я отклонил видео vc в ландшафтном режиме, презентация vc была только ненадолго в ландшафтном режиме.
Как было отмечено в комментарии к @Lyndsey Скотт ответить на это можно обойти, запрещая переходами в ландшафтном режиме, но комбинируя это и это я нашел более и более общее решение (ИМО). Это решение допускает вращение во всех vc, где вы помещаете canRotate(){} и не поворачиваете презентацию vc.

Swift 3:
В AppDelegate.swift:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
        if (rootViewController.responds(to: Selector(("canRotate")))) {
            // Unlock landscape view orientations for this view controller if it is not currently being dismissed
            if !rootViewController.isBeingDismissed{
                return .allButUpsideDown
            }
        }
    }

    // Only allow portrait (standard behaviour)
    return .portrait
}

private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
    if (rootViewController == nil) {
        return nil
    }
    if (rootViewController.isKind(of: UITabBarController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
    } else if (rootViewController.isKind(of: UINavigationController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
    } else if (rootViewController.presentedViewController != nil) {
        return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
    }
    return rootViewController
}

В каждом контроллере просмотра, где должно быть разрешено вращение:

func canRotate(){}

Ответ 6

Swift 3: добавьте код в AppDelegate.swift

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
            if (rootViewController.responds(to: Selector(("canRotate")))) {
                // Unlock landscape view orientations for this view controller
                return .allButUpsideDown;
            }
        }

        // Only allow portrait (standard behaviour)
        return .portrait;
    }

    private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
        if (rootViewController == nil) { return nil }
        if (rootViewController.isKind(of: (UITabBarController).self)) {
            return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
        } else if (rootViewController.isKind(of:(UINavigationController).self)) {
            return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
        } else if (rootViewController.presentedViewController != nil) {
            return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
        }
        return rootViewController
    }

Затем:

import UIKit

class ViewController: UIViewController {

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


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

        if (self.isMovingFromParentViewController) {
            UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
        }
    }

    func canRotate() -> Void {}

}

http://www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in-ios-slash-swift/

Ответ 7

SWIFT 4

Для UITabBarController мы можем использовать эту строку кода в AppDelegate.swift.

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let tabBarController = window?.rootViewController as? UITabBarController {
        if let tabBarViewControllers = tabBarController.viewControllers {
            if let projectsNavigationController = tabBarViewControllers[1] as? UINavigationController {
                if projectsNavigationController.visibleViewController is PickerViewController //use here your own ViewController class name {
                    return .all
                }
            }
        }
    }
    return .portrait
}

Ответ 8

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

Вот довольно быстрое решение, которое я нашел. Определите класс OrientationManager и используйте его для обновления поддерживаемых ориентаций в AppDelegate:

class OrientationManager {
    static var landscapeSupported: Bool = false
}

Затем в AppDelegate поместите ориентировки, которые вы хотите для этого конкретного случая:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if OrientationManager.landscapeSupported {
            return .allButUpsideDown
        }
        return .portrait
    }

Затем в ViewControllers, что вы хотите иметь несколько навигаций, обновите OrientationManager:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    OrientationManager.landscapeSupported = true
}

Кроме того, не забудьте обновить его еще раз, когда вы выйдете из этого ViewController:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    OrientationManager.landscapeSupported = false
    //The code below will automatically rotate your device orientation when you exit this ViewController
    let orientationValue = UIInterfaceOrientation.portrait.rawValue
    UIDevice.current.setValue(orientationValue, forKey: "orientation")
}

Надеюсь это поможет!

Ответ 9

Просто хотел поделиться своим решением как человек, который потратил слишком много времени на вращение одного контроллера представления в приложении:

var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get }

переопределение этого метода UIViewController помогло мне сделать то, что мне нужно.

  1. На контроллере представления, который вы хотите повернуть, сделайте это для поворота влево:

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return UIInterfaceOrientation.landscapeLeft }

  1. Убедитесь, что вы включили вращение в нужных направлениях из настроек проекта:

enter image description here

  1. И добавьте это в AppDelegate, чтобы отключить вращение других экранов:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) → UIInterfaceOrientationMask { return.portrait }

Ответ 10

Swift 5

Другой ответ, этот покрывает случай isBeingDismissed.

В AppDelegate:

    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if
            let vvc = navigationController?.visibleViewController,
            vvc is YOURViewControllerClassName &&
            !vvc.isBeingDismissed
        {
            return UIInterfaceOrientationMask.landscape
        } else {
            return UIInterfaceOrientationMask.portrait
        }
    }