如何在 iOS 8 中强制视图控制器方向?
Posted
技术标签:
【中文标题】如何在 iOS 8 中强制视图控制器方向?【英文标题】:How to force view controller orientation in iOS 8? 【发布时间】:2014-12-09 00:45:34 【问题描述】:在 ios 8 之前,我们将以下代码与 supportedInterfaceOrientations 和 shouldAutoRotate 委托方法结合使用,以强制应用程序方向为任何特定方向。我使用下面的代码 sn-p 以编程方式将应用程序旋转到所需的方向。首先,我正在更改状态栏方向。然后只需呈现并立即关闭模态视图即可将视图旋转到所需的方向。
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
但这在 iOS 8 中失败了。另外,我在堆栈溢出中看到了一些答案,人们建议我们应该从 iOS 8 开始避免这种方法。
更具体地说,我的应用程序是一种通用类型的应用程序。一共有三个控制器。
First View 控制器- 它应该支持 iPad 中的所有方向,并且只支持 iPhone 中的纵向(主页按钮向下)。
第二视图控制器- 它应该在所有情况下都只支持横向
第三视图控制器- 它应该在所有条件下仅支持横向
我们正在使用导航控制器进行页面导航。从第一个视图控制器,在按钮单击操作中,我们将第二个压入堆栈。因此,当第二个视图控制器到达时,无论设备方向如何,应用都应该只锁定横向。
下面是我在第二个和第三个视图控制器中的shouldAutorotate
和supportedInterfaceOrientations
方法。
-(NSUInteger)supportedInterfaceOrientations
return UIInterfaceOrientationMaskLandscapeRight;
-(BOOL)shouldAutorotate
return NO;
是否有任何解决方案或任何更好的方法来锁定 iOS 8 的特定方向的视图控制器。请帮助!!
【问题讨论】:
实现您在介绍的 VC 中提到的方法通常应该可以工作(至少这是我在iOS 8 中的经验)。也许您的特定设置会导致问题? 也许我可以让这个问题更清楚一点。我会稍微修改一下这个问题。 @VladimirGritsenko:请立即查看。我已经编辑过了。 问题中的代码不使用导航控制器的堆栈,而是使用模态表示,所以仍然不清楚你在做什么。我会说,在我们的代码中,从 shouldAutoRotate 返回 YES 并从 presented VC 中的 supportedInterfaceOrientations 返回所需的方向正确地定位了该 VC。 嗯,这并不是真正的失败,这只是概念上的重大变化。是否是好的改变完全是另一个话题。 【参考方案1】:对于 iOS 7 - 10:
目标-C:
[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];
斯威夫特 3:
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
只需在呈现的视图控制器的- viewDidAppear:
中调用它即可。
【讨论】:
这是不是私有 API。这是对 API 的不安全使用。您没有使用任何私有方法,而是使用“内部事物”。如果 Apple 更改“方向”的值,它会失败。更糟糕的是:如果 Apple 改变了“orientation”值的含义,你不知道你在改变什么硬设置值。 要禁用动画,请将[UIView setAnimationsEnabled:NO];
放入viewWillAppear
和[UIView setAnimationsEnabled:YES];
放入viewDidAppear
,相关:***.com/a/6292506/88597
不错的 hack,但问题在于,在设置新的方向值后没有触发 didRotateFromInterfaceOrientation(叹气)
在 iOS 9.2 中,这只是改变方向而不是锁定。
对于每个人在 90% 的时间里表现良好而在另外 10% 的时间里有问题,请在设置方向键后调用:[UINavigationController attemptRotationToDeviceOrientation];
【参考方案2】:
如果您在UINavigationController
或UITabBarController
内,方向旋转会稍微复杂一些。问题在于,如果视图控制器嵌入在这些控制器之一中,则导航或标签栏控制器具有优先权,并决定自动旋转和支持的方向。
我在 UINavigationController 和 UITabBarController 上使用了以下 2 个扩展,以便嵌入在其中一个控制器中的视图控制器做出决定。
赋予视图控制器权力!
斯威夫特 2.3
extension UINavigationController
public override func supportedInterfaceOrientations() -> Int
return visibleViewController.supportedInterfaceOrientations()
public override func shouldAutorotate() -> Bool
return visibleViewController.shouldAutorotate()
extension UITabBarController
public override func supportedInterfaceOrientations() -> Int
if let selected = selectedViewController
return selected.supportedInterfaceOrientations()
return super.supportedInterfaceOrientations()
public override func shouldAutorotate() -> Bool
if let selected = selectedViewController
return selected.shouldAutorotate()
return super.shouldAutorotate()
斯威夫特 3
extension UINavigationController
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask
return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
open override var shouldAutorotate: Bool
return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
extension UITabBarController
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask
if let selected = selectedViewController
return selected.supportedInterfaceOrientations
return super.supportedInterfaceOrientations
open override var shouldAutorotate: Bool
if let selected = selectedViewController
return selected.shouldAutorotate
return super.shouldAutorotate
现在您可以覆盖supportedInterfaceOrientations
方法,或者您可以在要锁定的视图控制器中覆盖shouldAutoRotate
,否则您可以省略其他视图控制器中的覆盖,您希望继承在中指定的默认方向行为您应用的 plist
禁用旋转
class ViewController: UIViewController
override func shouldAutorotate() -> Bool
return false
锁定特定方向
class ViewController: UIViewController
override func supportedInterfaceOrientations() -> Int
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
理论上这应该适用于所有复杂的视图控制器层次结构,但我注意到 UITabBarController 存在问题。出于某种原因,它想使用默认方向值。如果您有兴趣了解如何解决某些问题,请参阅以下博客文章:
Lock Screen Rotation
【讨论】:
我知道这是一篇很老的帖子,但你会把扩展代码放在哪里? 在 Objective-C 中会是什么样子? 这是 Swift 和 ObjC 的一个很好的解决方案。不明白为什么人们拒绝投票。你明白了,然后编写代码很容易。为什么抱怨? @Krodak ,在扩展中尝试将“-> Int”更改为“-> UIInterfaceOrientationMask”。对我有用。 这个想法和代码是完美的,我喜欢它,但是在使用 UINavigationController 时存在一个问题,从横向显示的 UIViewController 回到必须以纵向显示的 UIViewController。有什么想法吗?【参考方案3】:这对我有用:
https://developer.apple.com/library//ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation
在你的 viewDidAppear: 方法中调用它。
- (void) viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
[UIViewController attemptRotationToDeviceOrientation];
【讨论】:
非常有用,如果设备已经旋转并且您需要旋转视图控制器 很好的答案。当与接受的答案结合使用时,这对我每次在 Swift 和 iOS 9+ 中都很有效。 虽然我认为这不是问题的答案,但它确实帮助了我。【参考方案4】:我发现如果它是一个呈现的视图控制器,你可以覆盖preferredInterfaceOrientationForPresentation
斯威夫特:
override func supportedInterfaceOrientations() -> Int
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation
return UIInterfaceOrientation.LandscapeLeft
override func shouldAutorotate() -> Bool
return false
【讨论】:
似乎接受的答案只是触发了横向方向的更改。您在此处展示的是如何强制 视图控制器仅 处于横向状态,而不影响呈现视图控制器(这正是我所需要的)。谢谢。 @CliftonLabrum 你有没有做其他事情来强制only横向?使用相同的代码,视图控制器仍然能够旋转到另一个方向。 我后来意识到——你是对的。我还没有找到解决办法。 这对我有用。通过使用此代码(将横向替换为纵向),我能够将单个视图控制器保持在纵向模式。 +1 是的!这在 Xcode 7.3 和 Swift 2.2 中也适用于我。但仍需在 AppDelegate 中为supportedInterfaceOrientationsForWindow 定义func 应用程序。【参考方案5】:这种方式适用于 Swift 2 iOS 8.x:
PS(此方法不需要覆盖每个 viewController 上的方向函数,如 shouldautorotate,只需 AppDelegate 上的一个方法)
选中项目常规信息中的“需要全屏”。
所以,在 AppDelegate.swift 上创建一个变量:
var enableAllOrientation = false
所以,把这个函数也放进去:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask
if (enableAllOrientation == true)
return UIInterfaceOrientationMask.All
return UIInterfaceOrientationMask.Portrait
因此,在您项目的每个类中,您都可以在 viewWillAppear 中设置此 var:
override func viewWillAppear(animated: Bool)
super.viewWillAppear(animated)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.enableAllOrientation = true
如果您需要根据设备类型做出选择,您可以这样做:
override func viewWillAppear(animated: Bool)
super.viewWillAppear(animated)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
switch UIDevice.currentDevice().userInterfaceIdiom
case .Phone:
// It's an iPhone
print(" - Only portrait mode to iPhone")
appDelegate.enableAllOrientation = false
case .Pad:
// It's an iPad
print(" - All orientation mode enabled on iPad")
appDelegate.enableAllOrientation = true
case .Unspecified:
// Uh, oh! What could it be?
appDelegate.enableAllOrientation = false
【讨论】:
很好的解释【参考方案6】:首先 - 这是一个坏主意,一般来说,你的应用架构出了点问题,但是,sh..t happens
,如果是这样,你可以尝试像下面这样:
final class OrientationController
static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]
// MARK: - Public
class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask)
OrientationController.allowedOrientation = [orientationIdiom]
class func forceLockOrientation(_ orientation: UIInterfaceOrientation)
var mask:UIInterfaceOrientationMask = []
switch orientation
case .unknown:
mask = [.all]
case .portrait:
mask = [.portrait]
case .portraitUpsideDown:
mask = [.portraitUpsideDown]
case .landscapeLeft:
mask = [.landscapeLeft]
case .landscapeRight:
mask = [.landscapeRight]
OrientationController.lockOrientation(mask)
UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
比,AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
// do stuff
OrientationController.lockOrientation(.portrait)
return true
// MARK: - Orientation
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
return OrientationController.allowedOrientation
每当您想改变方向时,请执行以下操作:
OrientationController.forceLockOrientation(.landscapeRight)
注意:有时,设备可能无法从此类调用中更新,因此您可能需要执行以下操作
OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)
就是这样
【讨论】:
【参考方案7】:这应该适用于 iOS 6 以上,但我只在 iOS 8 上测试过。子类 UINavigationController
并覆盖以下方法:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
return UIInterfaceOrientationLandscapeRight;
- (BOOL)shouldAutorotate
return NO;
或者询问可见的视图控制器
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
return self.visibleViewController.preferredInterfaceOrientationForPresentation;
- (BOOL)shouldAutorotate
return self.visibleViewController.shouldAutorotate;
并在那里实现方法。
【讨论】:
我刚刚在运行 iOS 10.0 的 Xcode 8.2.1 中的应用程序上对此进行了测试,它可以正常工作。我的游戏菜单是第一个屏幕并且不会旋转;所有其他视图旋转。完美的!给它一个。我只需要 Mojo66 提供的 'preferredInterfaceOrientationForPresentation' 函数。【参考方案8】:这是对Sid Shah's answer 中的 cmets 的反馈,关于如何使用以下方法禁用动画:
[UIView setAnimationsEnabled:enabled];
代码:
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:NO];
[UIView setAnimationsEnabled:NO];
// *** #26357162 to force orientation
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
- (void)viewDidAppear:(BOOL)animated
[super viewDidAppear:NO];
[UIView setAnimationsEnabled:YES];
【讨论】:
如何将其用于肖像。【参考方案9】:如果您使用的是 navigationViewController,您应该为此创建自己的超类并覆盖:
- (BOOL)shouldAutorotate
id currentViewController = self.topViewController;
if ([currentViewController isKindOfClass:[SecondViewController class]])
return NO;
return YES;
这将禁用 SecondViewController 中的旋转,但如果您在设备处于纵向时按下 SecondViewController,那么您的 SecondViewController 将纵向显示模式。
假设您正在使用情节提要。您必须创建手动 segue (How to) 并在您的“onClick”方法中:
- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
[self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
这将在您的超类禁用自动旋转功能之前强制横向。
【讨论】:
【参考方案10】:在Xcode 8
上,方法将转换为属性,因此以下适用于Swift
:
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask
return UIInterfaceOrientationMask.portrait
override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation
return UIInterfaceOrientation.portrait
override public var shouldAutorotate: Bool
return true
【讨论】:
这会锁定方向吗? @bnussey 我想防止自动旋转并始终处于portrait
模式,无论 iPad 上的方向如何,shouldAutorotate
返回 true 我实现了这一点。【参考方案11】:
我尝试了很多解决方案,但最有效的解决方案如下:
在 ios 8 和 9 中无需编辑 info.plist
。
- (BOOL) shouldAutorotate
return NO;
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
Possible orientations from the Apple Documentation:
UIInterfaceOrientationUnknown
无法确定设备的方向。
UIInterfaceOrientationPortrait
设备处于纵向模式,设备直立, 底部的主页按钮。
UIInterfaceOrientationPortraitUpsideDown
设备处于纵向模式但上下颠倒,设备被握住 直立和顶部的主页按钮。
UIInterfaceOrientationLandscapeLeft
设备处于横向模式,设备保持直立, 左侧的主页按钮。
UIInterfaceOrientationLandscapeRight
设备处于横向模式,设备保持直立, 右侧的主页按钮。
【讨论】:
【参考方案12】:[iOS9+] 如果有人因为上述解决方案都不起作用而一直拖到这里, 如果你展示你想要改变方向的视图 通过segue,您可能想检查一下。
检查您的 segue 的演示文稿类型。 我的是“在当前情况下”。 当我将其更改为全屏时,它起作用了。
感谢@GabLeRoux,我找到了这个解决方案。
此更改仅在与上述解决方案结合使用时才有效。【讨论】:
【参考方案13】:Sids 和 Koreys 的答案组合对我有用。
扩展导航控制器:
extension UINavigationController
public override func shouldAutorotate() -> Bool
return visibleViewController.shouldAutorotate()
然后在单个视图上禁用旋转
class ViewController: UIViewController
override func shouldAutorotate() -> Bool
return false
在segue之前旋转到合适的方向
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
if (segue.identifier == "SomeSegue")
let value = UIInterfaceOrientation.Portrait.rawValue;
UIDevice.currentDevice().setValue(value, forKey: "orientation")
【讨论】:
你知道这是否有助于解决我的问题,即显示的视图控制器在旋转到纵向之前处于横向状态一秒钟,就像它应该总是那样?问题在这里:***.com/questions/30693964/…【参考方案14】:上面的***解决方案:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
当我在呈现的视图控制器的 viewDidAppear 中调用它时,它没有为我工作。但是,当我在呈现视图控制器的 preparForSegue 中调用它时,它确实起作用了。
(对不起,没有足够的声誉点来评论该解决方案,所以我不得不这样添加)
【讨论】:
我已经完成了这项工作,但是当从横向视图控制器转到纵向视图控制器时,应该以纵向显示的视图控制器在自行旋转之前简要地以横向显示。如果有人知道如何帮助我的问题在这里:***.com/questions/30693964/… @dwinnbrown at viewDidAppear 视图控制器已经可见。也许尝试从 viewDidLoad 代替? @Crashalot 我现在已经解决了这个问题。请查看我标记为正确的答案。 @dwinnbrown 您问题的链接已失效。更新?谢谢! @Crashalot 社区删除了它,但我已投票取消删除它。我会尽快通知你【参考方案15】:我的要求是
-
以纵向模式锁定所有视图
使用
AVPlayerViewController
播放视频
播放视频时,如果是横向,则允许屏幕向右横向旋转和向左横向旋转。如果是纵向,则仅将视图锁定为纵向模式。
首先,在AppDelegate.swift
中定义supportedInterfaceOrientationsForWindow
var portrait = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask
if portrait
return .Portrait
else
return .Landscape
其次,在您的主视图控制器中,定义以下函数
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask
print("\(#function)")
return .Portrait
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation
return .Portrait
override func shouldAutorotate() -> Bool
return false
那么,你需要继承AVPlayerViewController
class MyPlayerViewController: AVPlayerViewController
var size: CGSize?
var supportedOrientationMask: UIInterfaceOrientationMask?
var preferredOrientation: UIInterfaceOrientation?
override func viewDidLoad()
super.viewDidLoad()
if let size = size
if size.width > size.height
self.supportedOrientationMask =[.LandscapeLeft,.LandscapeRight]
self.preferredOrientation =.LandscapeRight
else
self.supportedOrientationMask =.Portrait
self.preferredOrientation =.Portrait
在MyPlayerViewController.swift
中重写这三个函数
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask
return self.supportedOrientationMask!
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation
return self.preferredOrientation!
由于用户可能会向左或向右旋转设备横向,我们需要将自动旋转设置为 true
override func shouldAutorotate() -> Bool
return true
最后,在您的视图控制器中创建MyPlayerViewController
实例并设置属性大小值。
let playerViewController = MyPlayerViewController()
// Get the thumbnail
let thumbnail = MyAlbumFileManager.sharedManager().getThumbnailFromMyVideoMedia(......)
let size = thumbnail?.size
playerViewController.size = size
使用正确的videoUrl
启动您的播放器,然后将您的播放器分配给playerViewController
。编码愉快!
【讨论】:
【参考方案16】:- (void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
[UIViewController attemptRotationToDeviceOrientation];
【讨论】:
【参考方案17】:似乎仍然存在一些关于如何最好地完成这项任务的争论,所以我想我会分享我的(工作)方法。在您的 UIViewController
实现中添加以下代码:
- (void) viewWillAppear:(BOOL)animated
[UIViewController attemptRotationToDeviceOrientation];
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
-(BOOL)shouldAutorotate
return NO;
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
return UIInterfaceOrientationMaskLandscapeLeft;
对于此示例,您还需要在项目设置中(或直接在info.plist
)中将允许的设备方向设置为“横向左”。如果您想要LandscapeLeft.
以外的其他内容,只需更改您想要强制的特定方向
对我来说,关键是 viewWillAppear
中的 attemptRotationToDeviceOrientation
调用 - 如果没有实际旋转设备,视图将无法正确旋转。
【讨论】:
不推荐使用的方法。【参考方案18】:根据Korey Hinton's answer
斯威夫特 2.2:
extension UINavigationController
public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask
return visibleViewController!.supportedInterfaceOrientations()
public override func shouldAutorotate() -> Bool
return visibleViewController!.shouldAutorotate()
extension UITabBarController
public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask
if let selected = selectedViewController
return selected.supportedInterfaceOrientations()
return super.supportedInterfaceOrientations()
public override func shouldAutorotate() -> Bool
if let selected = selectedViewController
return selected.shouldAutorotate()
return super.shouldAutorotate()
禁用旋转
override func shouldAutorotate() -> Bool
return false
锁定到特定方向
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask
return UIInterfaceOrientationMask.Portrait
【讨论】:
【参考方案19】:我在这里尝试了一些解决方案,重要的是要理解的是根视图控制器将确定它是否会旋转。
我创建了以下 objective-c 项目github.com/GabLeRoux/RotationLockInTabbedViewChild,其中一个工作示例为TabbedViewController
,其中一个子视图允许旋转,另一个子视图锁定为纵向。
它并不完美,但它可以工作,同样的想法应该适用于其他类型的根视图,例如NavigationViewController
。 :)
【讨论】:
【参考方案20】:根据@sid-sha 显示的解决方案,您必须将所有内容放入viewDidAppear:
方法中,否则您将不会触发didRotateFromInterfaceOrientation:
,因此类似于:
- (void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight)
NSNumber *value = [NSNumber numberWithInt:interfaceOrientation];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
【讨论】:
【参考方案21】:我的解决方案
在AppDelegate
:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask
if let topController = UIViewController.topMostViewController()
if topController is XXViewController
return [.Portrait, .LandscapeLeft]
return [.Portrait]
XXViewController
是您要支持横向模式的 ViewController。
那么Sunny Shah's solution 可以在你的XXViewController
在任何iOS 版本上工作:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
这是查找最顶层 ViewController 的实用函数。
extension UIViewController
/// Returns the current application's top most view controller.
public class func topMostViewController() -> UIViewController?
let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
return self.topMostViewControllerOfViewController(rootViewController)
/// Returns the top most view controller from given view controller's stack.
class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController?
// UITabBarController
if let tabBarController = viewController as? UITabBarController,
let selectedViewController = tabBarController.selectedViewController
return self.topMostViewControllerOfViewController(selectedViewController)
// UINavigationController
if let navigationController = viewController as? UINavigationController,
let visibleViewController = navigationController.visibleViewController
return self.topMostViewControllerOfViewController(visibleViewController)
// presented view controller
if let presentedViewController = viewController?.presentedViewController
return self.topMostViewControllerOfViewController(presentedViewController)
// child view controller
for subview in viewController?.view?.subviews ?? []
if let childViewController = subview.nextResponder() as? UIViewController
return self.topMostViewControllerOfViewController(childViewController)
return viewController
【讨论】:
【参考方案22】:使用它来锁定视图控制器方向,在 IOS 9 上测试:
// 锁定方向为横向
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
return UIInterfaceOrientationMaskLandscapeRight;
-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController
return UIInterfaceOrientationMaskLandscapeRight;
【讨论】:
【参考方案23】:我也有同样的问题,为此浪费了很多时间。所以现在我有了我的解决方案。我的应用设置仅支持纵向。但是,我的应用中的某些屏幕只需要横向。我通过在 AppDelegate 处设置一个变量 isShouldRotate 来修复它。 AppDelegate 处的函数:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int
if isShouldRotate == true
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
最后当 ViewControllerA 需要横向状态时。只需这样做:在推送/呈现之前 到 ViewControllerA 将 isShouldRotate 分配给 true。不要忘记在 viewWillDisappear 处弹出/关闭控制器将 isShouldRotate 分配给 false。
【讨论】:
【参考方案24】:对我来说,顶层 VC 需要实现方向覆盖。如果顶部的 VC 没有实现,则使用堆栈中的 VC 将无效。
VC-main
|
-> VC 2
|
-> VC 3
基本上在我的测试中,只听 VC-Main。
【讨论】:
【参考方案25】:看起来即使你在这里也有很多答案,没有一个人能满足我。我想强制定向,然后返回设备方向,但 [UIViewController attemptRotationToDeviceOrientation];
只是没有工作。使整个事情变得复杂的是,我根据一些答案将 shouldAutorotate 添加到 false 并且无法在所有情况下都获得正确旋转回来的预期效果。
这就是我所做的:
在他的 init 构造函数中调用控制器之前:
_userOrientation = UIDevice.currentDevice.orientation;
[UIDevice.currentDevice setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
[self addNotificationCenterObserver:@selector(rotated:)
name:UIDeviceOrientationDidChangeNotification];
所以我保存最后一个设备方向并注册方向更改事件。方向改变事件很简单:
- (void)rotated:(NSNotification*)notification
_userOrientation = UIDevice.currentDevice.orientation;
在视图中我只是强制回到我作为 userOreintation 的任何方向:
- (void)onViewDismissing
super.onViewDismissing;
[UIDevice.currentDevice setValue:@(_userOrientation) forKey:@"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
这也必须存在:
- (BOOL)shouldAutorotate
return true;
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
return UIInterfaceOrientationMaskPortrait;
导航控制器也必须委托给 shouldAutorotate 和 supportedInterfaceOrientations,但我相信大多数人已经拥有了。
PS:对不起,我使用了一些扩展和基类,但名称很有意义,所以概念是可以理解的,会做更多的扩展,因为它现在不太漂亮。
【讨论】:
以上是关于如何在 iOS 8 中强制视图控制器方向?的主要内容,如果未能解决你的问题,请参考以下文章