xcode 仅在一个 ViewController 中旋转

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28243241/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 06:34:34  来源:igfitidea点击:

Rotation only in one ViewController

iosxcodeswiftuiviewcontrollerrotation

提问by Armin Scheithauer

I am trying to rotate one view while all other views (5) are fixed to portrait. The reason is that in that one view I want the user to watch pictures which he saved before. I guess this is possible but so far I couldn't figure out how to achieve that. Can anyone help or give me a hint? I am programming that in Swift running on iOS8

我正在尝试旋转一个视图,而所有其他视图 (5) 都固定为纵向。原因是在那个视图中,我希望用户观看他之前保存的图片。我想这是可能的,但到目前为止我无法弄清楚如何实现这一目标。任何人都可以帮助或给我一个提示吗?我正在用在 iOS8 上运行的 Swift 编程

采纳答案by gandhi Mena

This is for Swift 3 and Swift 4. You can use the follow code in your AppDelegate.swift :

这适用于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
}

you can learn more in the original post: http://www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in-ios-slash-swift/

您可以在原帖中了解更多信息:http: //www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in​​-ios-slash -迅速/

回答by Lyndsey Scott

I'd recommend using supportedInterfaceOrientationsForWindowin your appDelegateto allow rotation only in that specific view controller, ex:

我建议supportedInterfaceOrientationsForWindow在您中使用以appDelegate仅允许在该特定视图控制器中旋转,例如:

Swift 4/Swift 5

斯威夫特 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
}

Note that if that SpecificViewControlleris in landscape before going to a portrait screen, the other view will still open in landscape. To circumvent this, I'd recommend disallowing transitions while that view is in landscape.

请注意,如果SpecificViewController在进入纵向屏幕之前处于横向状态,则另一个视图仍将以横向方式打开。为了避免这种情况,我建议在该视图处于横向时禁止转换。



Swift 3

斯威夫特 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)
}

回答by Cristian Pena

You can also do it in a protocol oriented way. Just create the protocol

您也可以以面向协议的方式进行。只需创建协议

protocol CanRotate {

}

Add the the same 2 methods in the AppDelegate in a more "swifty" way

以更“快捷”的方式在 AppDelegate 中添加相同的 2 个方法

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
}

And in every ViewController that you want a different behaviour, just add the protocol name in the definition of the class.

在您想要不同行为的每个 ViewController 中,只需在类的定义中添加协议名称。

class ViewController: UIViewController, CanRotate {}

If you want any particular combination, they you can add to the protocol a variable to override

如果你想要任何特定的组合,你可以在协议中添加一个变量来覆盖

protocol CanRotate {
    var supportedInterfaceOrientations: UIInterfaceOrientationMask
}

回答by Nikita Alexander

Sometimes when you're using a custom navigation flow (that may get really complex) the above-mentioned solutions may not always work. Besides, if you have several ViewControllers that need support for multiple orientations it may get quite tedious.

有时,当您使用自定义导航流(可能会变得非常复杂)时,上述解决方案可能并不总是有效。此外,如果您有多个需要支持多个方向的 ViewController,它可能会变得非常乏味。

Here's a rather quick solution I found. Define a class OrientationManagerand use it to update supported orientations in AppDelegate:

这是我找到的一个相当快速的解决方案。定义一个类OrientationManager并使用它来更新 AppDelegate 中支持的方向:

class OrientationManager {
    static var landscapeSupported: Bool = false
}

Then in AppDelegate put the orientations you want for that specific case:

然后在 AppDelegate 中放置您想要的特定情况的方向:

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

Then in the ViewControllers that you want to have multiple navigations update the OrientationManager:

然后在您想要多个导航的 ViewControllers 中更新OrientationManager

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

Also, don't forget to update it once again when you'll be exiting this ViewController:

另外,当您退出此 ViewController 时,不要忘记再次更新它:

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

Hope this helps!

希望这可以帮助!

Update:

更新:

You may just want to add a static functo your Orientation Support Managerclass:

您可能只想static funcOrientation Support Manager类中添加一个:

    static func setOrientation(_ orientation: UIInterfaceOrientation) {
        let orientationValue = orientation.rawValue
        UIDevice.current.setValue(orientationValue, forKey: "orientation")
        landscapeSupported = orientation.isLandscape
    }

Then you can call this function whenever you need to set the orientation back to portrait. That will also update the static landscapeSupportedvalue:

然后,您可以在需要将方向设置回纵向时调用此函数。这也将更新静态landscapeSupported值:

OSM.setOrientation(.portrait)

回答by Christian

Use the shouldAutorotateand the supportedInterfaceOrientationsmethod in the ViewController you want to display in landscape and portrait mode:

使用ViewController 中的shouldAutorotatesupportedInterfaceOrientations方法,以横向和纵向模式显示:

This method should override the storyboard-settings.

此方法应覆盖故事板设置。

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

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

回答by kuhr

I just faced a very similar problem where I wanted to present a video player in portrait and landscape mode whereas the rest of the app is portrait only. My main problem was that when I dismissed the video vc in landscape mode the presenting vc was only briefly in landscape mode.
As pointed out in the comment to @Lyndsey Scott's answerthis can be circumvented by disallowing transitions while in landscape mode, but by combining thisand thisI've found a better and more generic solution (IMO). This solution allows rotation in all vc where you put canRotate(){}and doesn't rotate the presenting vc.

我刚刚面临一个非常相似的问题,我想以纵向和横向模式呈现视频播放器,而应用程序的其余部分仅为纵向。我的主要问题是,当我在横向模式下关闭视频 vc 时,呈现的 vc 只是短暂地处于横向模式。
正如对@Lyndsey Scott 的回答的评论中指出的那样,这可以通过在横向模式下禁止转换来规避,但是通过将这个这个结合起来,我找到了一个更好、更通用的解决方案(IMO)。此解决方案允许在您放置的所有 vc 中旋转,canRotate(){}并且不旋转呈现的 vc。

Swift 3:
In AppDelegate.swift:

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
}

In each view controller where rotation should be allowed:

在每个允许旋转的视图控制器中:

func canRotate(){}

回答by PiterPan

SWIFT 4

斯威夫特 4

For UITabBarControllercan we use this line of code in AppDelegate.swift.

对于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
}

回答by Mohammad Razipour

Swift 3: Add code to AppDelegate.swift

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
    }

Then :

然后 :

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/

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

回答by Murat Yasar

Just wanted to share my solution as someone who has spent too much time rotating one view controller in the app:

只是想把我的解决方案分享给一个花了太多时间在应用程序中旋转一个视图控制器的人:

var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get }

overriding this UIViewController methodhelped me do what I need.

覆盖这个 UIViewController方法帮助我做我需要的。

  1. On the view controller that you want to rotate do this for landscape left rotation:
  1. 在要旋转的视图控制器上,为横向向左旋转执行此操作:

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return UIInterfaceOrientation.landscapeLeft }

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return UIInterfaceOrientation.landscapeLeft }

  1. Make sure you enable rotation in the desired directions from the project settings:
  1. 确保从项目设置中启用在所需方向上的旋转:

enter image description here

在此处输入图片说明

  1. And add this to AppDelegateto disable other screens' rotation:
  1. 并将其添加到AppDelegate以禁用其他屏幕的旋转:

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

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

回答by Jimmy_m

Swift 5

斯威夫特 5

Another answer, this one covers the isBeingDismissed case.

另一个答案,这个答案涵盖了 isBeingDismissed 案例。

In AppDelegate:

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