如何在iOS 8中强制视图控制器定向?


149

在iOS 8之前,我们将以下代码与supportedInterfaceOrientationsshouldAutoRotate委托方法结合使用,以将应用程序方向强制为任何特定方向。我使用下面的代码片段以编程方式将应用程序旋转到所需的方向。首先,我要更改状态栏的方向。然后,仅呈现并立即消除模态视图会将视图旋转到所需的方向。

[[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开始始终避免这种方法。

更具体地说,我的应用程序是通用类型的应用程序。共有三个控制器。

  1. First View控制器 -它应支持iPad中的所有方向,并且仅支持iPhone中的纵向(按下主页按钮)。

  2. Second View控制器 -在所有情况下都应仅支持横向景观

  3. Third View控制器 -在所有情况下都仅支持横向景观

我们正在使用导航控制器进行页面导航。从第一个视图控制器的按钮单击动作开始,我们将第二个推入堆栈。因此,当第二个视图控制器到达时,无论设备方向如何,应用程序都应仅锁定横向视图。

下面是我shouldAutorotatesupportedInterfaceOrientations第二个和第三个视图控制器中的方法。

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

有没有针对此问题的解决方案或将视图控制器锁定在iOS 8特定方向的更好方法,请帮忙!


通常,实现您在所介绍的 VC中提到的方法应该可以(至少这是我在iOS 8中的经验)。也许您的特定设置引起了问题?
弗拉基米尔·格里申科(Fladimir Gritsenko)2014年

也许我可以使这个问题更清楚一些。我将稍微编辑问题。
Rashmi Ranjan mallick

@VladimirGritsenko:请现在检查。我已经编辑了。
Rashmi Ranjan mallick

问题中的代码不使用导航控制器的堆栈,而是使用模式表示,因此仍不清楚您在做什么。我要说的是,在我们的代码中,应从shouldAutoRotate返回YES,并从所提供的 VC中的supportedInterfaceOrientations返回所需的方向来正确地定向该VC。
弗拉基米尔·格里申科(Fladimir Gritsenko)2014年

好吧,这并不是真正的失败,只是概念上的重大改变。好的改变完全是另一个话题。
Kegluneq 2014年

Answers:


315

对于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:在提供的视图控制器中调用它即可。


61
不是私有API。这是对API的不安全使用。您没有使用任何私有方法,而是使用了“内部事物”。如果Apple更改“方向”的值,它将失败。更糟糕的是:如果Apple更改了“方向”值的含义,则您不知道要硬设置该值的更改。
sonxurxo

4
要禁用动画,把 [UIView setAnimationsEnabled:NO];viewWillAppear[UIView setAnimationsEnabled:YES];viewDidAppear,相关:stackoverflow.com/a/6292506/88597
ohho

3
不错的技巧,但问题在于,在设置新的方向值(叹气)后,不触发didRotateFromInterfaceOrientation
loretoparisi

2
在iOS 9.2中,这只是更改方向,而不更改锁定。
Mark13426

2
对于每个拥有90%的时间表现良好的用户,以及其他10%的时间进行儿童越野游戏的用户,请在设置方向键后调用:[UINavigationController attemptRotationToDeviceOrientation];
Albert Renshaw

93

如果您在UINavigationController或中,方向旋转会稍微复杂一些UITabBarController。问题是,如果将视图控制器嵌入其中的一个控制器中,则导航或标签栏控制器将具有优先权,并就自动旋转和支持的方向做出决策。

我在UINavigationController和UITabBarController上使用以下2个扩展,以便嵌入在这些控制器之一中的视图控制器可以做出决定。

赋予View Controllers强大的力量!

迅捷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存在问题。由于某种原因,它想使用默认的方向值。如果您对学习如何解决某些问题感兴趣,请参阅以下博客文章:

锁屏旋转


1
我知道这是一篇很老的文章,但是您将扩展代码放在哪里?
dwinnbrown 2015年

7
减少对Objective-C问题的Swift唯一答案。
查理·斯科特·斯金纳

17
对于Swift和ObjC来说,这是一个不错的解决方案。不明白为什么人们拒绝投票。您有了主意,然后编写代码很容易。为什么要抱怨?

2
@Krodak,在扩展名中尝试将“-> Int”更改为“-> UIInterfaceOrientationMask”。为我做了把戏。
the_pantless_coder

2
我喜欢它的想法和代码很完美,但是使用UINavigationController时,从以横向显示的UIViewController回到必须以纵向显示的UIViewController时存在问题。有任何想法吗?
crisisGriega

24

这对我有用:

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

3
如果设备已经旋转并且您需要旋转视图控制器,则非常有用
avdyushin 2015年

2
好答案。与可接受的答案结合使用时,这对我和Swift和iOS 9+来说都是很好的选择。
AndyDunn '16

1
尽管我认为这不是所要回答的问题的答案,但它确实对我有所帮助。
阿卜杜拉赫曼·穆本·阿里

21

我发现,如果它是呈现的视图控制器,则可以覆盖 preferredInterfaceOrientationForPresentation

迅速:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

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

4
似乎已被接受的答案只是触发了景观方向的改变。您在此处显示的是如何强制视图控制器处于横向状态,而不影响呈现的视图控制器(这正是我所需要的)。谢谢。
克利夫顿·拉布鲁姆

1
@CliftonLabrum您是否还做过其他任何强制景观的操作?使用相同的代码,视图控制器仍然能够旋转到另一个方向。
Crashalot

后来我意识到,您是正确的。我还没有找到解决方法。
克利夫顿·拉布鲁姆

1
这对我有用。通过使用此代码,我能够将一个View Controller保持在纵向模式(用纵向替换横向)。+1
马克·巴拉索

是! 这在Xcode 7.3和Swift 2.2中也对我有用。但是仍然需要为AppDelegate中的supportInterfaceOrientationsForWindow定义func应用程序。
charles.cc.hsu 2016年

15

Swift 2 iOS 8.x中,这种方式对我有用:

PS(此方法不需要在每个viewController上覆盖诸如shouldautorotate之类的方向功能,而在AppDelegate上只是一个方法)

检查项目常规信息中的“要求全屏显示”。 在此处输入图片说明

因此,在AppDelegate.swift上创建一个变量:

var enableAllOrientation = false

因此,还要放这个func:

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

非常好的解释
Mihir Oza

11

首先-这是一个坏主意,通常来说,您的应用程序体系结构有问题,但是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)

就这样


9

这应该可以在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”功能。
菲利普·博尔赫斯

9

这是对Sid Shah的回答中有关如何使用以下方法禁用动画的评论的反馈:

[UIView setAnimationsEnabled:enabled];

码:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:NO];
    [UIView setAnimationsEnabled:NO];

    // Stackoverflow #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];
}

如何将其用于人像。
Muju

6

如果使用的是NavigationViewController,则应为此创建自己的超类并重写:

- (BOOL)shouldAutorotate {
  id currentViewController = self.topViewController;

  if ([currentViewController isKindOfClass:[SecondViewController class]])
    return NO;

  return YES;
}

这将禁用SecondViewController中的旋转,但是如果您在设备处于纵向方向时按下SecondViewController,则SecondViewController将以纵向模式显示。

假设您正在使用情节提要。你必须创建手动赛格瑞(如何),并在您的“点击”的方法:

- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
  NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
  [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
  [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}

这将在您的超类禁用自动旋转功能之前强制横向放置。


6

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

1
@bnussey我想防止自动旋转并始终处于portrait模式,无论iPad上的方向如何,shouldAutorotate返回true都实现了这一点。
阿里·莫曼·萨尼

4

我尝试了许多解决方案,但适用的解决方案如下:

无需info.plist在ios 8和ios 9中进行编辑。

- (BOOL) shouldAutorotate {
    return NO;
}   

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}

Apple文档可能的方向

UIInterfaceOrientationUnknown

无法确定设备的方向。

UIInterfaceOrientationPortrait

设备处于纵向模式,设备直立放置,并且主页按钮位于底部。

UIInterfaceOrientationPortraitUpsideDown

该设备处于纵向模式,但颠倒过来,直立握住设备,并且主页按钮位于顶部。

UIInterfaceOrientationLandscapeLeft

设备处于横向模式,设备直立放置,而主页按钮位于左侧。

UIInterfaceOrientationLandscapeRight

设备处于横向模式,设备直立放置,并且主页按钮位于右侧。


3

Sids和Koreys答案的组合对我有用。

扩展导航控制器:

extension UINavigationController {
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

然后在单个视图上禁用旋转

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

并在旋转前旋转到适当的方向

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "SomeSegue")
    {
        let value = UIInterfaceOrientation.Portrait.rawValue;
        UIDevice.currentDevice().setValue(value, forKey: "orientation")
    }
}

您知道这是否有助于解决我的问题,即所显示的视图控制器在像应该一直旋转到纵向之前先横向放置一秒钟?问题就在这里:stackoverflow.com/questions/30693964/...
dwinnbrown

3

上面的顶级解决方案:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

当我在显示的视图控制器的viewDidAppear中调用它时,对我没有用。但是,当我在呈现视图控制器的preparForSegue中调用它时,它确实起作用了。

(对不起,没有足够的声誉积分来评论该解决方案,所以我不得不这样添加它)


我已经完成了这项工作,但是当从横向视图控制器转到纵向视图控制器时,应该以纵向显示的视图控制器会在横向旋转之前短暂地横向显示。如果有人知道如何帮助我的问题是在这里:stackoverflow.com/questions/30693964/...
dwinnbrown

viewDidAppear上的@dwinnbrown视图控制器已可见。也许尝试从viewDidLoad代替?
Crashalot

@Crashalot我现在已解决此问题。请查看我标记为正确答案。
dwinnbrown 2015年

@dwinnbrown您问题的链接已死。更新?谢谢!
Crashalot 2015年

@Crashalot社区将其删除,但我已投票决定删除它。我会尽快通知您
dwinnbrown,2015年

3

[iOS9 +]如果上述解决方案均无效,但有人将其一直拖到此处,并且如果您提出要通过segue更改方向的视图,则可能要进行检查。

检查您的segue的显示类型。我的是“在当前背景下”。当我将其更改为“全屏”时,它可以工作。

感谢@GabLeRoux,我找到了这个解决方案。

  • 仅当与上述解决方案结合使用时,此更改才有效。

2

我的要求是

  1. 将所有视图锁定为纵向模式
  2. 用于AVPlayerViewController播放视频

播放视频时,如果它是风景,则让屏幕向右旋转风景和向左旋转风景。如果是纵向模式,则仅将视图锁定为纵向模式。

首先,supportedInterfaceOrientationsForWindowAppDelegate.swift

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。编码愉快!



1

关于如何最好地完成此任务似乎仍存在一些争论,因此我认为我会分享我的(工作中)方法。在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.

对我来说,关键是attemptRotationToDeviceOrientation呼入viewWillAppear-如果没有物理旋转设备,视图将无法正确旋转。


不推荐使用的方法。
萨奇布·奥马尔

1

根据Korey Hinton的回答

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

1

我在这里尝试了一些解决方案,需要了解的重要一点是,由根视图控制器确定其是否会旋转。

我创建了以下Objective-C项目github.com/GabLeRoux/RotationLockInTabbedViewChild,其中包含一个TabbedViewController其中其中一个子视图可以旋转,而另一个子视图纵向锁定。

这不是完美的方法,但它可以工作,相同的想法也可以用于其他类型的根视图,例如NavigationViewController。:)

子视图锁定父方向


0

根据@ 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"];
    }
}

0

我的解决方案

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的解决方案可以在您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
    }

}

0

使用此功能锁定在IOS 9上测试的视图控制器方向:

//将方向锁定到正确的横向

-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
    return UIInterfaceOrientationMaskLandscapeRight;
}

0

我有同样的问题,浪费了很多时间。所以现在我有了解决方案。我的应用程序设置为只支持肖像only.However,一些屏幕到我的应用程序需要有山水画only.I修复它由具有可变isShouldRotateAppDelegate中。以及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的操作。


0

对我来说,顶层VC需要实现方向替代。如果顶级VC未实现,则向下使用VC将无效。

VC-main
    |
    -> VC 2
        |
        -> VC 3

本质上,在我的测试中,仅收听VC-Main。


0

看来即使您在这里有这么多答案,没人能满足我的需求。我想强制定位,然后回到设备定位,但是[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:抱歉,我使用了一些扩展名和基类,但是名称很有意义,因此概念是可以理解的,因为现在还不太漂亮,所以将进行更多扩展。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.