【问题标题】:How to force view controller orientation in iOS 8?如何在 iOS 8 中强制视图控制器方向?
【发布时间】:2014-12-09 00:45:34
【问题描述】:

在 iOS 8 之前,我们将以下代码与 supportedInterfaceOrientationsshouldAutoRotate 委托方法结合使用,以强制应用程序方向为任何特定方向。我使用下面的代码 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 开始避免这种方法。

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

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

  2. 第二视图控制器- 它应该在所有情况下都只支持横向

  3. 第三视图控制器- 它应该在所有条件下仅支持横向

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

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

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

是否有任何解决方案或任何更好的方法来锁定 iOS 8 的特定方向的视图控制器。请帮助!!

【问题讨论】:

  • 实现您在介绍的 VC 中提到的方法通常应该可以工作(至少这是我在iOS 8 中的经验)。也许您的特定设置会导致问题?
  • 也许我可以让这个问题更清楚一点。我会稍微修改一下这个问题。
  • @VladimirGritsenko:请立即查看。我已经编辑过了。
  • 问题中的代码不使用导航控制器的堆栈,而是使用模态表示,所以仍然不清楚你在做什么。我会说,在我们的代码中,从 shouldAutoRotate 返回 YES 并从 presented VC 中的 supportedInterfaceOrientations 返回所需的方向正确地定位了该 VC。
  • 嗯,这并不是真正的失败,这只是概念上的重大变化。是否是好的改变完全是另一个话题。

标签: ios objective-c ios8 uinavigationcontroller autorotate


【解决方案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】:

如果您在UINavigationControllerUITabBarController 内,方向旋转会稍微复杂一些。问题在于,如果视图控制器嵌入在这些控制器之一中,则导航或标签栏控制器具有优先权,并决定自动旋转和支持的方向。

我在 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】:

          我的要求是

          1. 以纵向模式锁定所有视图
          2. 使用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 需要横向状态时。只需这样做:在推送/呈现之前ViewControllerAisShouldRotate 分配给 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:对不起,我使用了一些扩展和基类,但名称很有意义,所以概念是可以理解的,会做更多的扩展,因为它现在不太漂亮。

                            【讨论】: