防止导航控制器中的某些视图控制器旋转

时间:2013-04-30 20:02:27

标签: iphone objective-c uinavigationcontroller rotation uiinterfaceorientation

我有一个导航控制器,可以同时显示两个视图控制器。它们是分层的,最前面的控制器可以向下拖动以显示下面的控制器。 我的应用程序委托已配置,因此应用程序将仅在显示后面的视图时允许界面方向,如下所示。

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if (self.revealNavigationController.isViewRevealed)
    {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }

    return UIInterfaceOrientationMaskPortrait;
}

当然,这会导致前视图控制器和后视图控制器在旋转设备时旋转,但我只对旋转后视图控制器感兴趣。 有没有办法在最前面的视图控制器中完全禁用旋转?

3 个答案:

答案 0 :(得分:1)

您需要使用iOS5中添加的视图控制器包含API。基本上,您需要做的是当您不再希望它参与旋转事件时删除您的一个视图控制器,并在它再次准备好时将其添加回来。样本将是......

@implementation AXRotationDemoViewController

- (id)init
{
    if ((self = [super init]))
    {
        self.oneViewController = [[AXLoggingViewController alloc] init];
        self.oneViewController.interfaceOrientations = UIInterfaceOrientationMaskPortrait;

        self.twoViewController = [[AXLoggingViewController alloc] init];
        self.twoViewController.interfaceOrientations = UIInterfaceOrientationMaskAllButUpsideDown;
    }

    return self;
}

- (void)viewDidLoad
{
    [self.oneViewController willMoveToParentViewController:self];
    [self addChildViewController:self.oneViewController];
    [self.view addSubview:self.oneViewController.view];
    [self.oneViewController didMoveToParentViewController:self];

    [self.twoViewController willMoveToParentViewController:self];
    [self addChildViewController:self.twoViewController];
    [self.view addSubview:self.twoViewController.view];
    [self.twoViewController didMoveToParentViewController:self];

    self.oneViewController.view.backgroundColor = [UIColor redColor];
    self.twoViewController.view.backgroundColor = [UIColor greenColor];

    UIButton * showBackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [showBackButton setTitle:@"Toggle Back/Front" forState:UIControlStateNormal];
    [showBackButton addTarget:self action:@selector(_toggle:) forControlEvents:UIControlEventTouchUpInside];
    [showBackButton sizeToFit];
    showBackButton.center = self.view.center;
    [self.view addSubview:showBackButton];
}

- (void)_toggle:(id)sender
{
    if ([self.childViewControllers containsObject:self.oneViewController])
    {
        [self.oneViewController.view removeFromSuperview];
        [self.oneViewController removeFromParentViewController];
    }
    else
    {
        [self.oneViewController willMoveToParentViewController:self];
        [self addChildViewController:self.oneViewController];
        [self.view addSubview:self.oneViewController.view];
        [self.oneViewController didMoveToParentViewController:self];

        UIWindow * window = self.view.window;
        UIViewController * hack = window.rootViewController;
        window.rootViewController = nil;
        window.rootViewController = hack;
    }
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    CGRect halfScreenFrame = self.view.bounds;
    halfScreenFrame.size.height /= 2;

    self.oneViewController.view.frame = halfScreenFrame;
    self.twoViewController.view.frame = CGRectOffset(halfScreenFrame, 0, halfScreenFrame.size.height);
}

- (NSUInteger)supportedInterfaceOrientations
{
    if ([self.childViewControllers containsObject:self.oneViewController])
        return self.oneViewController.supportedInterfaceOrientations;

    return self.twoViewController.supportedInterfaceOrientations;
}

@end

但是你可能会注意到,没有正式的方法可以告诉iOS你已经改变了supportedInterfaceOrientations的值,所以你最好的选择是a)使用上面例子中的hack来强制iOS重做所有内容或b)在设备再次处于纵向状态之前,不要让用户关闭后视图。

如果这不能很好地解释事情,那么我将sample放在一起。

答案 1 :(得分:0)

是的,看看UIViewController中的-supportedInterfaceOrientations方法。您返回一个UIInterfaceOrientationMask位掩码,指定您希望UIViewController子类支持的方向。

答案 2 :(得分:0)

axiixc建议的解决方案通常更好,因此根据您的问题,您应该look at his answer但是,这并没有解决我的问题。我有一个UINavigationController,其中我将视图控制器的视图作为索引0的子视图插入。这样,视图将在后面。然后我让UINavigationBar拖动,这样当它拖下来时,它会显示后面的视图。然后,最前面的视图将随导航栏移动。 根据axiixc的建议,我没有设法使用iOS 5引入的视图控制器包含API。

相反,我从导航控制器中删除了视图,并在应用程序启动时将其直接添加到UIWindow,我自己处理了此视图的旋转,并禁用了所有其他视图的旋转(即我在导航控制器上禁用它。)

这是我在-application:didFinishLaunchingWithOptions:

中添加视图的方式
self.revealViewController = [[RevealViewController alloc] init];
[self.window insertSubview:self.revealViewController.view atIndex:0];

然后,在此之后我注册了UIDeviceOrientationDidChangeNotification

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];

我的didRotate:看起来像这样:(这是受到StackOverflow的另一个答案的启发,我现在再也找不到了,抱歉)

- (void)didRotate:(NSNotification *)notification
{
    // Only rotate if the view is revealed
    if (self.revealNavigationController.isViewRevealed)
    {
        UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
        [self updateForDeviceOrientation:orientation animated:YES];
    }
}

我致电-updateForDeviceOrientation:animated:

- (void)updateForDeviceOrientation:(UIDeviceOrientation)orientation animated:(BOOL)animated
{
    CGFloat degrees = 0.0f;
    switch (orientation)
    {
        case UIDeviceOrientationLandscapeLeft:
            degrees = 90.0f;
            break;
        case UIDeviceOrientationLandscapeRight:
            degrees = -90.0f;
            break;
        case UIDeviceOrientationPortrait:
            degrees = 0.0f;
            break;
        default:
            break;
    }

    CGFloat duration = (animated) ? [UIApplication sharedApplication].statusBarOrientationAnimationDuration : 0.0f;

    __weak typeof(self) weakSelf = self;
    [UIView animateWithDuration:duration animations:^{
        // Rotate view
        weakSelf.revealViewController.view.transform = CGAffineTransformIdentity;
        weakSelf.revealViewController.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(degrees));

        // Resize view for rotation
        CGFloat width, height;
        if (UIDeviceOrientationIsLandscape(orientation))
        {
            width = MAX(CGRectGetWidth(weakSelf.revealViewController.view.bounds), CGRectGetHeight(weakSelf.revealViewController.view.bounds));
            height = MIN(CGRectGetWidth(weakSelf.revealViewController.view.bounds), CGRectGetHeight(weakSelf.revealViewController.view.bounds));
        }
        else
        {
            width = MIN(CGRectGetWidth(weakSelf.revealViewController.view.bounds), CGRectGetHeight(weakSelf.revealViewController.view.bounds));
            height = MAX(CGRectGetWidth(weakSelf.revealViewController.view.bounds), CGRectGetHeight(weakSelf.revealViewController.view.bounds));
        }

        CGSize newSize = CGSizeMake(width, height);

        CGRect viewBounds = weakSelf.revealViewController.view.bounds;
        viewBounds.size = newSize;
        weakSelf.revealViewController.view.bounds = viewBounds;

        CGRect viewFrame = weakSelf.revealViewController.view.frame;
        viewFrame.size = newSize;
        weakSelf.revealViewController.view.bounds = viewFrame;
    }];
}