iOS:禁用子视图的自动旋转

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7353789/
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 21:25:40  来源:igfitidea点击:

iOS: Disable Autorotation for a Subview

iosipaduivieworientationdevice-orientation

提问by Jason George

I have a nested view hierarchy for an iPad application that supports orientation changes. It looks similiar to the following.

我有一个支持方向更改的 iPad 应用程序的嵌套视图层次结构。它看起来类似于以下内容。

UIViewController
    UIView
        - UIView
            - UIImageView (disable rotation)
            - UIImageView
            - UIView (disable rotation)
        - UIView
        - UIView
        ...

I would like to lock the orientation for some of my subviews, while allowing others to auto-rotate and resize. I can't quite seem to figure out how to accomplish this.

我想锁定某些子视图的方向,同时允许其他子视图自动旋转和调整大小。我似乎无法弄清楚如何实现这一点。

One approach seems to be rotating the subviews manually within willAnimateRotationToInterfaceOrientation:. That's not particularly attractive given the SDK is executing a rotation that I would just be undoing.

一种方法似乎是在willAnimateRotationToInterfaceOrientation:. 鉴于 SDK 正在执行我将要撤消的轮换,这并不是特别有吸引力。

Is there a way to simply disable orientation changes for subviews or some other method to restructure my hierarchy?

有没有办法简单地禁用子视图的方向更改或其他一些方法来重构我的层次结构?

回答by Stuart

Autorotation is handled by a view's UIViewController (shouldAutorotateToInterfaceOrientation:), so one approach is to arrange your hierarchy such that rotatable views are managed by one view controller, and non-rotatable views by another view controller. Both of these UIViewController's root views then need adding to the window/superview.

自动旋转由视图的 UIViewController ( shouldAutorotateToInterfaceOrientation:) 处理,因此一种方法是安排层次结构,使可旋转视图由一个视图控制器管理,而不可旋转视图由另一个视图控制器管理。这两个 UIViewController 的根视图都需要添加到窗口/超级视图中。

The subtlety here is that if you have two view controller's views on the same level (i.e. added via addSubview:), only the first view controller (usually the window's rootViewController) will receive the shouldAutorotateToInterfaceOrientation:message.

这里的微妙之处在于,如果您在同一级别有两个视图控制器的视图(即通过 添加addSubview:),则只有第一个视图控制器(通常是窗口的rootViewController)会收到shouldAutorotateToInterfaceOrientation:消息。

I used this approach myself to achieve a toolbar that rotates, while the main view does not.

我自己使用这种方法来实现旋转的工具栏,而主视图则没有。

Apple's Technical Q&A QA1688 ("Why won't my UIViewController rotate with the device?")talks a little bit about this issue.

Apple 的 Technical Q&A QA1688(“为什么我的 UIViewController 不随设备旋转?”)稍微谈到了这个问题。



Update for iOS 6:

iOS 6 更新:

Autorotation now uses UIViewController's shouldAutorotateand supportedInterfaceOrientationsmethods. shouldAutorotatereturns YESby default, but remember that a view controller other than the rootViewControllerwhose view is a direct subview of the window will NOT receive rotation callbacks anyway.

Autorotation 现在使用UIViewController'sshouldAutorotatesupportedInterfaceOrientations方法。默认情况下shouldAutorotate返回YES,但请记住,除了rootViewController其视图是窗口的直接子视图之外的视图控制器无论如何都不会接收旋转回调。



Sample Code for iOS 6:

iOS 6 示例代码:

Create a new project using the "Single View Application" template, and ensure "Use Storyboards" is checked. We'll use the provided ViewControllerclass as the rotating view controller (rename it if you like!), and create a second UIViewControllersubclass called NonRotatingViewController. Although this view controller will never even receive the rotation callbacks, for completeness and clarity add the following code in NonRotatingViewController.m:

使用“Single View Application”模板创建一个新项目,并确保选中“Use Storyboards”。我们将使用提供的ViewController类作为旋转视图控制器(如果你愿意,可以重命名它!),并创建一个UIViewController名为NonRotatingViewController. 尽管这个视图控制器永远不会收到旋转回调,但为了完整和清晰,在 中添加以下代码NonRotatingViewController.m

- (BOOL)shouldAutorotate
{
    return NO;
}

In the MainStoryboardfile, drag out a new view controller object and set its class to NonRotatingViewController, and set its Storyboard ID to "NonRotatingVC". While you're there, change the rotating view controller view's background color to clear (the non rotating view will be added underneath this one), and add a label to each view. In AppDelegate.m, add the following code:

MainStoryboard文件中,拖出一个新的视图控制器对象并将其类设置为NonRotatingViewController,并将其 Storyboard ID 设置为“NonRotatingVC”。当您在那里时,将旋转视图控制器视图的背景颜色更改为清除(非旋转视图将添加在此视图下方),并为每个视图添加一个标签。在 中AppDelegate.m,添加以下代码:

#import "NonRotatingViewController.h"

// ...
// ...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    NonRotatingViewController *nonRotatingVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"NonRotatingVC"];
    [self.window addSubview:nonRotatingVC.view];
    return YES;
}

This is just instantiating a non rotating view controller and adding its view directly to the window (N.B. at this point the window's rootViewControllerhas already been set by the storyboard).

这只是实例化一个非旋转视图控制器并将其视图直接添加到窗口(注意此时窗口rootViewController已经由故事板设置)。

Run the project. Rotate the device and marvel at the sight of one label rotating while the other stays still!

运行项目。旋转设备并惊叹于一个标签旋转而另一个保持静止的景象!



Sample Code pre iOS 6:

iOS 6 之前的示例代码:

I did this in a new project - a new View-based Application will do just fine. Add two new view controllers: RotatingViewControllerand NonRotatingViewController. Inside each of their nibs I just added a label to describe whether the view should rotate or not. Add the following code:

我在一个新项目中这样做了 - 一个新的基于视图的应用程序就可以了。添加两个新的视图控制器:RotatingViewControllerNonRotatingViewController. 在他们的每个笔尖中,我只是添加了一个标签来描述视图是否应该旋转。添加以下代码:

'RotatingViewController.m'

' RotatingViewController.m'

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}


'NonRotatingViewController.m'


' NonRotatingViewController.m'

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationPortrait) {    // Or whatever orientation it will be presented in.
        return YES;
    }
    return NO;
}


'AppDelegate.m'


' AppDelegate.m'

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    RotatingViewController *rotating = [[RotatingViewController alloc] initWithNibName:@"RotatingViewController" bundle:nil];
    self.rotatingViewController = rotating;
    [rotating release];

    NonRotatingViewController *nonRotating = [[NonRotatingViewController alloc] initWithNibName:@"NonRotatingViewController" bundle:nil];
    self.nonRotatingViewController = nonRotating;
    [nonRotating release];

    [self.window addSubview:self.rotatingViewController.view];
    [self.window insertSubview:self.nonRotatingViewController.view belowSubview:self.rotatingViewController.view];

    [self.window makeKeyAndVisible];

    return YES;
}

I hope this helps.

我希望这有帮助。

回答by mahboudz

Here is another way. Just place this code into your viewController viewDidLoad:

这是另一种方式。只需将此代码放入您的 viewController viewDidLoad 中:

    YourAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
        // the view you don't want rotated (there could be a heierarchy of views here):
    UIView *nonRotatingView = [[UIView alloc] initWithFrame:CGRectMake(100,0,30,500)];
    nonRotatingView.backgroundColor = [UIColor purpleColor];

        // make sure self.view and its children are transparent so you can see through to this view that will not be rotated behind self.view.

    [delegate.window insertSubview:nonRotatingView  belowSubview:self.view];

        // you can't put it in the front using:
        //    [delegate.window insertSubview:nonRotatingView aboveSubview:self.view];
        // It will show up the same as before

    // you should declare nonRotatingView as a property so you can easily access it for removal, etc.

回答by ffraenz

My approach of solving this problem is doing a countermeasure using UINotificationto detect auto rotation and rotating the view the other way round.

我解决这个问题的方法是做一个对策,使用UINotification检测自动旋转并以相反的方式旋转视图。

Find the complete code here:
https://gist.github.com/ffraenz/5945301

在这里找到完整的代码:https:
//gist.github.com/ffraenz/5945301

- (void)orientationDidChangeNotificationReceived:(NSNotification *)notification
{
    // find out needed compass rotation
    //  (as a countermeasure to auto rotation)
    float rotation = 0.0;

    if (self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
        rotation = M_PI;
    else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
        rotation = M_PI / 2.0;
    else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
        rotation = M_PI / (- 2.0);

    // rotate compass without auto rotation animation
    //  iOS rotation animation duration is 0.3
    //  this excludes the compassView from the auto rotation
    //  (same effect as in the camera app where controls do rotate and camera viewport don't)
    [UIView animateWithDuration:0.3 animations:^(void) {
        self.compassView.transform = CGAffineTransformMakeRotation(rotation);
    }];
}