如何在设备方向改变时实现UIViewController的旋转?

7
我的应用程序有大约10个不同的UIViewControllers,其中只有一个在设备旋转时我想切换到横向模式。(其余所有视图,我都想保持为竖屏。)
为了在那个视图上实现旋转,我需要实现它的控制器的'shouldAutorotate'方法并返回YES。由于这个视图是通过导航控制器访问的,所以我还需要创建一个UINavigationController的子类来实现'shouldAutorotate'并返回YES。
这个解决方案有效,但太过完美。我发现我推入到我的UINavigationController子类中的所有UIViewControllers都会响应旋转,即使我实现了'shouldAutorotate'并返回NO。(记住:我只想让一个特定的UIViewController响应旋转,而不是导航控制器堆栈中的每一个视图。)
所以,我的问题是:我该如何最好地做到这一点?我能想到的所有解决方案似乎都很笨重,并且更糟糕的是,似乎都不起作用。
非常感谢。
4个回答

2
当您实现UINavigationController时,此类是控制将推送到堆栈中的所有子视图控制器的父控制器。因此,RootViewController是唯一可以对自动旋转说“是”或“否”的控制器。即使在子视图控制器中传递了Yes以进行自动旋转,它们也不起作用!
这是UINavigationController的本质。所以要更改它,您有两个选择:
1-手动操作它,这需要您通过一些繁琐的代码。
2-更改设计,使其更兼容UINavigationController。应该旋转的单个视图应由RootViewController(而不是Navigation Root View Controller - 它们名称相同,但完全不同)调用,该视图托管NavController。当设备旋转时,它将将NavController推入视图或其他视图。
3-另一种方法也可以工作,但不建议使用,因为它违反了MVC的概念,即您的NavController可以侦听通知。那个可以和应该旋转的特定子视图可以发出通知 - 例如rotateMe,一旦NavController听到它就会旋转。
正如我所说,它可以工作,但它违反了MVC模型 - 这对苹果来说没问题,但从编程角度来看不建议这样做。
如果您需要进一步解释,请让我知道。

1
我通过拥有一个根视图控制器(可以是UITabBarController),并在其viewDidLoad方法中订阅旋转事件来实现这一点:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(didRotate:)
                                                      name:@"UIDeviceOrientationDidChangeNotification" 
                                                      object:nil];

然后在 didRotate: 方法中,我会查看旋转发生时哪个视图控制器可见,以及手机的方向:

- (void) didRotate:(NSNotification *)notification { 
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

/*
    DEVICE JUST ROTATED TO PORTRAIT MODE

 orientation == UIDeviceOrientationFaceUp ||
 orientation == UIDeviceOrientationFaceDown

 */
if(orientation == UIDeviceOrientationPortrait) {





/*
    DEVICE JUST ROTATED TO LANDSCAPE MODE
 */
}else if(orientation == UIInterfaceOrientationLandscapeLeft ||
        orientation == UIInterfaceOrientationLandscapeRight) {






}

}

在didRotate:方法中,你可以查看哪个视图控制器是可见的,并从那里执行你想要的操作。
当特定的视图控制器可见并且手机旋转为横屏时,我会以横屏模式呈现一个模态视图控制器。如果有其他任何视图控制器可见,则忽略该事件。
我强制我的模态视图控制器在其viewWillAppear方法中以横屏模式显示 - 如果有人需要此代码,我可以提供它。
希望这能帮到你。
戴夫

1

仅在导航控制器子类上返回YES,如果[[navController topViewController] isKindOfClass:[RotatingViewController class]]


0

我曾经看到过使用你现在这种方式的例子,但是无法使其正常工作。我从苹果的例子中找到了更好的方法。基本上,你需要实现一个presentModalViewController并创建另一个视图。UIKit会进行基本的旋转动画,并在视图之间淡入淡出。你必须将旋转的视图实现为委托类,以便它可以回调到其调用类来关闭它并更新方向。

- (void)orientationChanged:(NSNotification *)notification
{
    // We must add a delay here, otherwise we'll swap in the new view
    // too quickly and we'll get an animation glitch
    NSLog(@"orientationChanged");
    [self performSelector:@selector(updateLandscapeView) withObject:nil afterDelay:0];
}

然后显示一个景观屏幕:

- (void)updateLandscapeView
{
PortraitView *portraitView = [[PortraitView alloc] init];
portraitView.delegate = self;
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
    [self presentModalViewController: portraitView animated:YES];
    isShowingLandscapeView = YES;
    }
else if (deviceOrientation == UIDeviceOrientationPortrait && isShowingLandscapeView)
{
    [self dismissModalViewControllerAnimated:YES];
    isShowingLandscapeView = NO;
    }
[portraitView release];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接