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

时间:2011-09-08 20:03:40

标签: ios ipad uiview orientation device-orientation

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

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

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

一种方法似乎是在willAnimateRotationToInterfaceOrientation:内手动旋转子视图。鉴于SDK正在执行我将要撤消的轮换,这并不是特别有吸引力。

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

3 个答案:

答案 0 :(得分:22)

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

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

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

Apple's Technical Q&A QA1688 ("Why won't my UIViewController rotate with the device?")对此问题进行了一些讨论。


iOS 6更新:

自动旋转现在使用shouldAutorotateToInterfaceOrientation:的{​​{1}}和UIViewController方法。默认情况下,shouldAutorotate会返回supportedInterfaceOrientations,但请记住,视图是窗口的直接子视图的shouldAutorotate以外的视图控制器无论如何都不会收到旋转回调。


iOS 6示例代码:

使用“单一视图应用程序”模板创建一个新项目,并确保选中“使用故事板”。我们将使用提供的YES类作为旋转视图控制器(如果您愿意,可以重命名它!),并创建名为rootViewController的第二个ViewController子类。虽然此视图控制器永远不会收到旋转回调,但为了完整性和清晰度,在UIViewController中添加以下代码:

NonRotatingViewController

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

NonRotatingViewController

这只是实例化一个非旋转的视图控制器并将其视图直接添加到窗口(此时N.B.窗口的AppDelegate.m已经由故事板设置了。)

运行项目。旋转设备并惊叹于一个标签旋转而另一个标签静止不动!


iOS 6之前的示例代码:

我在一个新项目中做到了这一点 - 一个新的基于视图的应用程序会做得很好。添加两个新的视图控制器:#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; } rootViewController。在他们的每个笔尖里面,我只添加了一个标签来描述视图是否应该旋转。添加以下代码:

'RotatingViewController'

NonRotatingViewController


'RotatingViewController.m'

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


'NonRotatingViewController.m'

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

我希望这会有所帮助。

答案 1 :(得分:10)

这是另一种方式。只需将此代码放入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.

答案 2 :(得分:4)

我解决这个问题的方法是使用UINotification来检测自动旋转并反过来旋转视图。

在此处查找完整代码:
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);
    }];
}