iOS 6:如何将某些视图限制为纵向并允许其他视图旋转?

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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:27:21  来源:igfitidea点击:

iOS 6: How do I restrict some views to portrait and allow others to rotate?

iosiphoneios6autorotate

提问by Harald B?geholz

I have an iPhone app that uses a UINavigationControllerto present a drill-down interface: First one view, then another, up to four levels deep. I want the first three views restricted to portrait orientation and only the last view should be allowed to rotate to landscape. When returning from the fourth view to the third and the fourth view was in landscape orientation I want everything to rotate back to portrait.

我有一个 iPhone 应用程序,它使用 aUINavigationController来呈现一个向下钻取的界面:第一个视图,然后是另一个视图,最多四层。我希望前三个视图仅限于纵向,并且只允许最后一个视图旋转为横向。当从第四个视图返回到第三个并且第四个视图处于横向时,我希望所有内容都旋转回纵向。

In iOS 5 I simply defined shouldAutorotateToInterfaceOrientation:in each of my view controllers to return YES for the allowable orientations. Everything worked as described above, including the return to portrait even if the device was being held in landscape orientation when returning from view controller #4 to #3.

在 iOS 5 中,我只是shouldAutorotateToInterfaceOrientation:在我的每个视图控制器中定义为允许的方向返回 YES。一切都按上述方式工作,包括从视图控制器 #4 返回到 #3 时,即使设备处于横向,也返回到纵向。

In iOS 6 all view controllers rotate to landscape, breaking those that weren't meant to. The iOS 6 release notes say

在 iOS 6 中,所有的视图控制器都旋转到横向,打破了那些不想要的。iOS 6 发行说明说

More responsibility is moving to the app and the app delegate. Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate. [...] The system asks the top-most full-screen view controller (typically the root view controller) for its supported interface orientations whenever the device rotates or whenever a view controller is presented with the full-screen modal presentation style. Moreover, the supported orientations are retrieved only if this view controller returns YES from its shouldAutorotatemethod. [...] The system determines whether an orientation is supported by intersecting the value returned by the app's supportedInterfaceOrientationsForWindow:method with the value returned by the supportedInterfaceOrientationsmethod of the top-most full-screen controller.

更多的责任正在转移到应用程序和应用程序委托上。现在,iOS 容器(例如UINavigationController)不会咨询他们的孩子来确定他们是否应该自动旋转。[...] 每当设备旋转或视图控制器以全屏模式呈现样式呈现时,系统都会向最顶层的全屏视图控制器(通常是根视图控制器)询问其支持的界面方向。此外,仅当此视图控制器从其shouldAutorotate方法返回 YES 时,才会检索支持的方向。[...] 系统通过将应用程序的supportedInterfaceOrientationsForWindow:方法返回的值supportedInterfaceOrientations与最顶层全屏控制器的方法返回的值相交来确定是否支持某个方向。

So I subclassed UINavigationController, gave my MainNavigationControllera boolean property landscapeOKand used this to return the allowable orientations in supportedInterfaceOrientations. Then in each of my view controllers' viewWillAppear:methods I have a line like this

所以我子类化UINavigationController,给了我MainNavigationController一个布尔属性,landscapeOK并用它来返回supportedInterfaceOrientations. 然后在我的每个视图控制器的viewWillAppear:方法中,我都有这样的一行

    [(MainNavigationController*)[self navigationController] setLandscapeOK:YES];

to tell my MainNavigationControllerthe desired behavior.

告诉我MainNavigationController想要的行为。

Here comes the question:If I now navigate to my fourth view in portrait mode and turn the phone over it rotates to landscape. Now I press the back button to return to my third view which is supposed to work portrait only. But it doesn't rotate back. How do I make it do that?

问题来了:如果我现在以纵向模式导航到我的第四个视图并将手机翻转过来,它会旋转到横向。现在我按下后退按钮返回到我的第三个视图,它应该只适用于纵向。但它不会旋转回来。我如何让它做到这一点?

I tried

我试过

    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]

in the viewWillAppearmethod of my third view controller, but it doesn't do anything. Is this the wrong method to call or maybe the wrong place to call it or should I be implementing the whole thing in a totally different way?

viewWillAppear我的第三个视图控制器的方法中,但它没有做任何事情。这是错误的调用方法还是错误的调用位置,还是我应该以完全不同的方式实现整个事情?

回答by Flo

I had the same problem and found a solution that works for me. To make it work, it is notsufficient to implement - (NSUInteger)supportedInterfaceOrientationsin your UINavigationController. You also need to implement this method in your controller #3, which is the first one to be portrait-only after popping controller #4. So, I have the following code in my UINavigationController:

我遇到了同样的问题,并找到了适合我的解决方案。为了使它的工作,它是不是足以实现- (NSUInteger)supportedInterfaceOrientations你的UINavigationController。您还需要在控制器 #3 中实现此方法,这是弹出控制器 #4 后第一个仅纵向显示的方法。所以,我的 UINavigationController 中有以下代码:

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if (self.isLandscapeOK) {
        // for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

In view controller #3, add the following:

在视图控制器 #3 中,添加以下内容:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

You don't need to add anything to your view controllers #1, #2, and #4. This works for me, I hope it will help you.

您不需要向视图控制器 #1、#2 和 #4 添加任何内容。这对我有用,我希望它会帮助你。

回答by Zaraki

Add a CustomNavigationController

添加自定义导航控制器

Override these methods in it:

覆盖其中的这些方法:

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

Now add all orientations in the plist

现在在 plist 中添加所有方向

enter image description here

在此处输入图片说明

In the view controller add only the required ones:

在视图控制器中只添加所需的:

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

these methods override the navigation controller methods

这些方法覆盖导航控制器方法

回答by Brian

After looking through every answer in countless similar questions on SO, none of the answers worked for me, but they did give me some ideas. Here's how I ended up solving the problem:

在查看了关于 SO 的无数类似问题的每个答案后,没有一个答案对我有用,但它们确实给了我一些想法。这是我最终解决问题的方法:

First, make sure your Supported Interface Orientations in your project's target contain all orientations that you want for your rotating view.

首先,确保项目目标中支持的界面方向包含旋转视图所需的所有方向。

enter image description here

在此处输入图片说明

Next, make a category of UINavigationController(since Apple says not to subclass it):

接下来,创建一个类别UINavigationController(因为 Apple 说不要将其子类化):

@implementation UINavigationController (iOS6AutorotationFix)

-(BOOL)shouldAutorotate {
    return [self.topViewController shouldAutorotate];
}

@end

Import that category and the view controller that you want to be able to rotate (which I'll call RotatingViewController) to your highest level view controller, which should contain your navigation controller. In that view controller, implement shouldAutorotateas follows. Note that this should not be the same view controller that you want to rotate.

将该类别和您希望能够旋转的视图控制器(我将称之为RotatingViewController)导入到您的最高级视图控制器,其中应包含您的导航控制器。在该视图控制器中,实现shouldAutorotate如下。请注意,这不应与您要旋转的视图控制器相同。

-(BOOL)shouldAutorotate {

    BOOL shouldRotate = NO;

    if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) {
        shouldRotate = [navigationController.topViewController shouldAutorotate];
    }

    return shouldRotate;
}

Finally, in your RotatingViewController, implement shouldAutorotateand supportedInterfaceOrientationsas follows:

最后,在您的RotatingViewController, 实现shouldAutorotatesupportedInterfaceOrientations如下:

-(BOOL)shouldAutorotate {
    // Preparations to rotate view go here
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate
}

The reason you need to do this is because iOS 6 gives control of rotation to the root view controller instead of the top view controlller. If you want an individual view's rotation to behave differently than other views in the stack, you need to write a specific case for it in the root view controller.

您需要这样做的原因是因为 iOS 6 将旋转控制权交给了根视图控制器而不是顶视图控制器。如果您希望单个视图的旋转行为与堆栈中的其他视图不同,则需要在根视图控制器中为其编写特定案例。

回答by micmdk

I don't have enough reputation to comment on @Brian's answer so I'll add my note here.

我没有足够的声誉来评论@Brian 的回答,所以我会在这里添加我的笔记。

Brian mentioned that iOS6 gives the rotation control to the rootViewController - this could not only be a UINavigationController as mentioned but also a UITabBarController, which it was for me. My structure looks like this:

Brian 提到 iOS6 为 rootViewController 提供了旋转控制——这不仅可以是前面提到的 UINavigationController,还可以是 UITabBarController,它是给我的。我的结构是这样的:

  • UITabBarController
    • UINavigationController
      • UIViewControllers ...
    • UINavigationController
      • UIViewControllers ...
  • UITabBarController
    • 导航控制器
      • UIViewControllers ...
    • 导航控制器
      • UIViewControllers ...

So I added the methods first in a custom UITabBarController, then in a custom UINavigationController and then lastly in the specific UIViewController.

所以我首先在自定义的 UITabBarController 中添加了方法,然后在自定义的 UINavigationController 中,最后在特定的 UIViewController 中添加了这些方法。

Example from the UITabBarController and UINavigationController:

来自 UITabBarController 和 UINavigationController 的示例:

- (BOOL)shouldAutorotate {
    return [self.viewControllers.lastObject shouldAutorotate];
}

- (NSUInteger)supportedInterfaceOrientations {
    return [self.viewControllers.lastObject supportedInterfaceOrientations];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return [self.viewControllers.lastObject shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation];
}

回答by Harald B?geholz

I'd like to give a partial answer to my own question. I found the following line of code, used in the viewWillAppearmethod of my third UIViewController, to work:

我想对我自己的问题给出部分答案。我发现在viewWillAppear我的第三个方法中使用的以下代码行UIViewController可以工作:

[[UIDevice currentDevice] 
      performSelector:NSSelectorFromString(@"setOrientation:") 
           withObject:(id)UIInterfaceOrientationPortrait];

But I don't really like this solution. It is using a trick to assign to a read-only property which according to Apple documentation represents the physicalorientation of the device. It's like telling the iPhone to jump to the correct orientation in the hand of the user.

但我真的不喜欢这个解决方案。它使用一种技巧来分配只读属性,根据 Apple 文档,该属性表示设备的物理方向。这就像告诉 iPhone 跳转到用户手中的正确方向。

I am very tempted to leave this in my app since it simply works. But it doesn't feel right so I'd like to leave the question open for a clean solution.

我很想把它留在我的应用程序中,因为它很简单。但感觉不对,所以我想把这个问题留给一个干净的解决方案。

回答by ASHISHT

This is I am using for orientation support in ios 6.0

这是我用于 ios 6.0 中的方向支持

-(BOOL)shouldAutorotate{
    return YES;
}  

 - (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskAll;
}


- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{  
  return UIInterfaceOrientationPortrait;
}

回答by Reeder32

Being that this is a highly viewed thread. I thought I would add what I believe is the easiest answer. This works for ios8 and up

因为这是一个高度关注的线程。我想我会添加我认为最简单的答案。这适用于 ios8 及更高版本

-(BOOL)shouldAutorotate
{
    return YES;
}

and

-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}

That's it. Enjoy!

就是这样。享受!

Oh, and my ViewControllers are embedded in a navigation controller, which I did not need to subclass or configure in any way.

哦,我的 ViewController 嵌入在导航控制器中,我不需要以任何方式对其进行子类化或配置。

回答by Ramakrishna

I've solved the same kind of issue.

我已经解决了同样的问题。

If you are using the UINavigationControllerto push the view controllers, you have to set the methods below.

如果您使用UINavigationController来推送视图控制器,则必须设置以下方法。

extension UINavigationController{

    override open var shouldAutorotate: Bool {

        if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
        {
            return true
        }
        return false
    }

    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
        {
            return .portrait
        }
        return .landscapeRight

    }
    override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

        if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
        {
            return .portrait
        }
        return .landscapeRight
    }
}

In place of LoginViewControlleruse which UIViewControlleryou want show. In my case, I want to show the LoginViewControllerin the Portraitmode other ViewControllersin landscapemode.

代替您想要展示的LoginViewController用途UIViewController。在我的情况,我想展示LoginViewControllerPortrait模式以外ViewControllerslandscape模式。

回答by vedrano

You can implement and override shouldAutorotate() and supportedInterfaceOrientations var in all of your View Controller classes that should be presented in a different orientations than ones defined in PLIST of your app.

您可以在所有视图控制器类中实现和覆盖 shouldAutorotate() 和 supportedInterfaceOrientations var,这些类应该以与应用程序的 PLIST 中定义的方向不同的方向呈现。

However, in a nontrivial User Interface you might face a problem to add it in dozens of classes and you do not want to make all of them subclass of several common that supports it (MyBaseTableViewController, MyBaseNavigationController and MyBaseTabBarController).

然而,在一个非平凡的用户界面中,您可能会遇到将它添加到数十个类中的问题,并且您不希望将所有这些类都设为支持它的几个公共类(MyBaseTableViewController、MyBaseNavigationController 和 MyBaseTabBarController)的子类。

Since you cannot override those method/var on UIViewController directly, you may do that on its subclasses that are typically base classes of yours like UITableViewController, UINavigationController and UITabBarController.

由于您无法直接覆盖 UIViewController 上的这些方法/变量,您可以在其子类上执行此操作,这些子类通常是您的基类,如 UITableViewController、UINavigationController 和 UITabBarController。

So you may implement a few extensions and still setup MyPreciousViewController to show in a different orientations than all others like this Swift 4 code snippet:

因此,您可以实现一些扩展并仍然设置 MyPreciousViewController 以显示与所有其他类似的 Swift 4 代码片段不同的方向:

extension UITableViewController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

    if let last = self.navigationController?.childViewControllers.last,
        last != self {
            return last.supportedInterfaceOrientations
    } else {
        return [.portrait]
    }
    }
}

extension MyPreciousViewController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

    return [.portrait,.landscape]
    }
}


extension UINavigationController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        return [.portrait]
    }
}


extension UITabBarController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        return [.portrait]
    }
}

回答by vedrano

You want to Force iOS 6 app portrait only then you can add to a UIViewController subclass below methods

你想强制 iOS 6 应用程序肖像,然后你可以添加到 UIViewController 子类下面的方法

- (BOOL)shouldAutorotate {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return YES;
    } else {
        return NO;
    }
}


- (NSUInteger)supportedInterfaceOrientations {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return UIInterfaceOrientationMaskAll;
    } else {
        return UIInterfaceOrientationMaskPortrait;
    }
}