只轮换一次ViewController
Rotation only in one ViewController
我正在尝试旋转一个视图,而所有其他视图 (5) 都固定为纵向。原因是在那个视图中我希望用户观看他之前保存的图片。我想这是可能的,但到目前为止我还不知道如何实现。任何人都可以帮助或给我提示吗?
我正在 Swift 运行 iOS8
中编程
在ViewController中使用 shouldAutorotate
和 supportedInterfaceOrientations
方法来显示横向和纵向模式:
此方法应覆盖故事板设置。
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> Int {
return UIInterfaceOrientation.Portrait.rawValue | UIInterfaceOrientation.LandscapeLeft.rawValue | UIInterfaceOrientation.LandscapeRight.rawValue
}
我建议在您的 appDelegate
中使用 supportedInterfaceOrientationsForWindow
以仅允许在该特定视图控制器中旋转,例如:
Swift 4/Swift 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
在进入纵向屏幕之前处于横向状态,则另一个视图仍将以横向方式打开。为了避免这种情况,我建议在该视图处于横向时禁止转换。
Swift 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)
}
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 {}
}
我刚刚遇到了一个非常相似的问题,我想以纵向和横向模式显示视频播放器,而应用程序的其余部分仅为纵向。我的主要问题是,当我以横向模式关闭视频 vc 时,呈现 vc 只是短暂地处于横向模式。
正如在对 this can be circumvented by disallowing transitions while in landscape mode, but by combining this and this 的评论中指出的那样,我找到了一个更好、更通用的解决方案 (IMO)。此解决方案允许在您放置 canRotate(){}
的所有 vc 中旋转并且不旋转呈现 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(){}
您也可以以面向协议的方式进行。
只需创建协议
protocol CanRotate {
}
以更"swifty"的方式在 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
}
并且在您想要不同行为的每个 ViewController 中,只需在 class 的定义中添加协议名称即可。
class ViewController: UIViewController, CanRotate {}
如果你想要任何特定的组合,你可以在协议中添加一个变量来覆盖
protocol CanRotate {
var supportedInterfaceOrientations: UIInterfaceOrientationMask
}
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
}
这适用于 Swift 4 和 Swift 5。您可以在 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
}
然后您可以通过重写 shouldAutorotate
使自定义 UIViewController 旋转
有时当您使用自定义导航流程(这可能会变得非常复杂)时,上述解决方案可能并不总是有效。此外,如果您有多个 ViewController 需要支持多个方向,它可能会变得非常乏味。
这是我找到的一个相当快速的解决方案。定义一个 class 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
}
然后在 ViewController 中您想要多个导航更新 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's orientation when you exit this ViewController
let orientationValue = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(orientationValue, forKey: "orientation")
}
希望对您有所帮助!
更新:
您可能只想添加一个 static func
到您的 Orientation Support Manager
class:
static func setOrientation(_ orientation: UIInterfaceOrientation) {
let orientationValue = orientation.rawValue
UIDevice.current.setValue(orientationValue, forKey: "orientation")
landscapeSupported = orientation.isLandscape
}
然后您可以在需要将方向设置回纵向时调用此函数。这也将更新静态 landscapeSupported
值:
OSM.setOrientation(.portrait)
只是想分享我的解决方案,因为有人花了太多时间在应用程序中旋转一个视图控制器:
var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get }
覆盖这个 UIViewController method 帮助我完成了我需要的事情。
- 在要旋转的视图控制器上执行此操作以横向向左旋转:
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return UIInterfaceOrientation.landscapeLeft
}
- 确保从项目设置中启用所需方向的旋转:
- 并将此添加到 AppDelegate 以禁用其他屏幕的旋转:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return .portrait
}
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
}
}
Swift 5 使用标记协议
这里几个答案的组合版本,我认为是更 readable/elegant 的实现。 (源自此处的早期答案,并非我的原创作品!)
protocol RotatableViewController {
// No content necessary, marker protocol
}
class MyViewController: UIViewController, RotatableViewController {
// normal content... nothing more required
}
extension AppDelegate {
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
guard
let rootVc = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
rootVc.isBeingDismissed == false,
let _ = rootVc as? RotatableViewController
else {
return .portrait // Some condition not met, so default answer for app
}
// Conditions met, is rotatable:
return .allButUpsideDown
}
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
}
}
None 这些答案对我有用。从根本上说,AppDelegate 的方法不允许指定 viewController。所以要么 topMost ViewController 是可旋转的,在这种情况下整个视图控制器层次结构都会旋转,或者什么都不会旋转。
不过,我确实在
中找到了一个有希望的答案
它引用了https://developer.apple.com/library/archive/qa/qa1890/_index.html
结合大家的想法,我写出了我认为最优雅的方式。
结果:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return (UIApplication.getTopViewController() as? Rotatable == nil) ? .portrait : .allButUpsideDown
}
将这个扩展添加到你的项目中,它不仅对这个有用:
extension UIApplication {
class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return getTopViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return getTopViewController(base: presented)
}
return base
}
}
创建协议:
protocol Rotatable {}
并实施它:
class ViewController: UIViewController, Rotatable {
}
解决方案Swift5.1
在 App delegate 中实现这个方法
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let topController = UIApplication.topViewController() {
if topController.isKind(of: YourSpecificViewController.self) {
return .all
}
return .portrait
}
return .portrait
}
然后添加此扩展以获得最顶部ViewController
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
} else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
return topViewController(base: selected)
} else if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
我正在尝试旋转一个视图,而所有其他视图 (5) 都固定为纵向。原因是在那个视图中我希望用户观看他之前保存的图片。我想这是可能的,但到目前为止我还不知道如何实现。任何人都可以帮助或给我提示吗? 我正在 Swift 运行 iOS8
中编程在ViewController中使用 shouldAutorotate
和 supportedInterfaceOrientations
方法来显示横向和纵向模式:
此方法应覆盖故事板设置。
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> Int {
return UIInterfaceOrientation.Portrait.rawValue | UIInterfaceOrientation.LandscapeLeft.rawValue | UIInterfaceOrientation.LandscapeRight.rawValue
}
我建议在您的 appDelegate
中使用 supportedInterfaceOrientationsForWindow
以仅允许在该特定视图控制器中旋转,例如:
Swift 4/Swift 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
在进入纵向屏幕之前处于横向状态,则另一个视图仍将以横向方式打开。为了避免这种情况,我建议在该视图处于横向时禁止转换。
Swift 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)
}
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 {}
}
我刚刚遇到了一个非常相似的问题,我想以纵向和横向模式显示视频播放器,而应用程序的其余部分仅为纵向。我的主要问题是,当我以横向模式关闭视频 vc 时,呈现 vc 只是短暂地处于横向模式。
正如在对 canRotate(){}
的所有 vc 中旋转并且不旋转呈现 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(){}
您也可以以面向协议的方式进行。 只需创建协议
protocol CanRotate {
}
以更"swifty"的方式在 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
}
并且在您想要不同行为的每个 ViewController 中,只需在 class 的定义中添加协议名称即可。
class ViewController: UIViewController, CanRotate {}
如果你想要任何特定的组合,你可以在协议中添加一个变量来覆盖
protocol CanRotate {
var supportedInterfaceOrientations: UIInterfaceOrientationMask
}
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
}
这适用于 Swift 4 和 Swift 5。您可以在 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
}
然后您可以通过重写 shouldAutorotate
有时当您使用自定义导航流程(这可能会变得非常复杂)时,上述解决方案可能并不总是有效。此外,如果您有多个 ViewController 需要支持多个方向,它可能会变得非常乏味。
这是我找到的一个相当快速的解决方案。定义一个 class 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
}
然后在 ViewController 中您想要多个导航更新 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's orientation when you exit this ViewController
let orientationValue = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(orientationValue, forKey: "orientation")
}
希望对您有所帮助!
更新:
您可能只想添加一个 static func
到您的 Orientation Support Manager
class:
static func setOrientation(_ orientation: UIInterfaceOrientation) {
let orientationValue = orientation.rawValue
UIDevice.current.setValue(orientationValue, forKey: "orientation")
landscapeSupported = orientation.isLandscape
}
然后您可以在需要将方向设置回纵向时调用此函数。这也将更新静态 landscapeSupported
值:
OSM.setOrientation(.portrait)
只是想分享我的解决方案,因为有人花了太多时间在应用程序中旋转一个视图控制器:
var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get }
覆盖这个 UIViewController method 帮助我完成了我需要的事情。
- 在要旋转的视图控制器上执行此操作以横向向左旋转:
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return UIInterfaceOrientation.landscapeLeft
}
- 确保从项目设置中启用所需方向的旋转:
- 并将此添加到 AppDelegate 以禁用其他屏幕的旋转:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return .portrait
}
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
}
}
Swift 5 使用标记协议
这里几个答案的组合版本,我认为是更 readable/elegant 的实现。 (源自此处的早期答案,并非我的原创作品!)
protocol RotatableViewController {
// No content necessary, marker protocol
}
class MyViewController: UIViewController, RotatableViewController {
// normal content... nothing more required
}
extension AppDelegate {
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
guard
let rootVc = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
rootVc.isBeingDismissed == false,
let _ = rootVc as? RotatableViewController
else {
return .portrait // Some condition not met, so default answer for app
}
// Conditions met, is rotatable:
return .allButUpsideDown
}
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
}
}
None 这些答案对我有用。从根本上说,AppDelegate 的方法不允许指定 viewController。所以要么 topMost ViewController 是可旋转的,在这种情况下整个视图控制器层次结构都会旋转,或者什么都不会旋转。
不过,我确实在
它引用了https://developer.apple.com/library/archive/qa/qa1890/_index.html
结合大家的想法,我写出了我认为最优雅的方式。
结果:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return (UIApplication.getTopViewController() as? Rotatable == nil) ? .portrait : .allButUpsideDown
}
将这个扩展添加到你的项目中,它不仅对这个有用:
extension UIApplication {
class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return getTopViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return getTopViewController(base: presented)
}
return base
}
}
创建协议:
protocol Rotatable {}
并实施它:
class ViewController: UIViewController, Rotatable {
}
解决方案Swift5.1
在 App delegate 中实现这个方法
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let topController = UIApplication.topViewController() {
if topController.isKind(of: YourSpecificViewController.self) {
return .all
}
return .portrait
}
return .portrait
}
然后添加此扩展以获得最顶部ViewController
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
} else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
return topViewController(base: selected)
} else if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}