我有一个使用UINavigationController
来展示向下钻取界面的iPhone应用程序:第一个视图,然后是另一个视图,最多四个级别。我希望前三个视图仅限于纵向,只允许最后一个视图旋转到横向。当从第四个视图返回到第三个视图并且第四个视图处于横向时,我希望所有内容都旋转回肖像。
在iOS 5中,我只是在每个视图控制器中定义shouldAutorotateToInterfaceOrientation:
,以便为允许的方向返回YES。所有工作都如上所述,包括返回肖像,即使从视图控制器#4返回到#3时设备被横向保持。
在iOS 6中,所有视图控制器都会旋转到横向,打破那些不适合的视图。 iOS 6发行说明说
更多责任转移到应用和应用代表。现在,iOS容器(例如
UINavigationController
)不会咨询他们的孩子以确定他们是否应该自动旋转。 [...]无论何时设备旋转或者每当视图控制器呈现全屏模态演示样式时,系统都会询问最顶层的全屏视图控制器(通常是根视图控制器)的支持接口方向。此外,仅当此视图控制器从其shouldAutorotate
方法返回YES时,才会检索支持的方向。 [...]系统通过将应用程序的supportedInterfaceOrientationsForWindow:
方法返回的值与最顶层全屏控制器的supportedInterfaceOrientations
方法返回的值相交来确定是否支持方向。 / p>
所以我将UINavigationController
子类化,给我的MainNavigationController
一个布尔属性landscapeOK
并使用它来返回supportedInterfaceOrientations
中的允许方向。然后在我的每个视图控制器的viewWillAppear:
方法中,我都有这样的一行
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
告诉我的MainNavigationController
期望的行为。
以下是问题:如果我现在以纵向模式导航到第四个视图并将手机翻过来,则旋转到横向。现在我按下后退按钮返回我的第三个视图,该视图应该仅适用于肖像。但它不会回转。我该怎么做呢?
我试过
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]
在我的第三个视图控制器的viewWillAppear
方法中,但它没有做任何事情。这是错误的调用方法,也可能是错误的调用方法,或者我应该以完全不同的方式实现整个事情?
答案 0 :(得分:95)
我遇到了同样的问题,并找到了适合我的解决方案。
为了使它工作,不足以在你的UINavigationController中实现- (NSUInteger)supportedInterfaceOrientations
。
您还需要在控制器#3中实现此方法,这是第一个在弹出控制器#4后仅为纵向的控制器。
所以,我在UINavigationController中有以下代码:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if (self.isLandscapeOK) {
// for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
在视图控制器#3中,添加以下内容:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
您无需向视图控制器#1,#2和#4添加任何内容。 这对我有用,我希望它会对你有帮助。
答案 1 :(得分:67)
添加 CustomNavigationController
在其中覆盖这些方法:
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
现在在plist中添加所有方向
在视图控制器中只添加所需的:
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
这些方法会覆盖导航控制器方法
答案 2 :(得分:9)
在SO上查看无数类似问题的每个答案后,没有一个答案对我有用,但他们确实给了我一些想法。以下是我最终解决问题的方法:
首先,确保项目目标中的“支持的界面方向”包含旋转视图所需的所有方向。
接下来,制作一个UINavigationController
的类别(因为Apple说不要将其子类化):
@implementation UINavigationController (iOS6AutorotationFix)
-(BOOL)shouldAutorotate {
return [self.topViewController shouldAutorotate];
}
@end
将您希望能够旋转的类别和视图控制器(我将调用RotatingViewController
)导入到应包含导航控制器的最高级别视图控制器。在该视图控制器中,按如下方式实现shouldAutorotate
。请注意,这不应与您要旋转的视图控制器相同。
-(BOOL)shouldAutorotate {
BOOL shouldRotate = NO;
if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) {
shouldRotate = [navigationController.topViewController shouldAutorotate];
}
return shouldRotate;
}
最后,在您的RotatingViewController
中,按照以下方式实施shouldAutorotate
和supportedInterfaceOrientations
:
-(BOOL)shouldAutorotate {
// Preparations to rotate view go here
return YES;
}
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate
}
您需要这样做的原因是因为iOS 6控制旋转到根视图控制器而不是顶视图控制器。如果您希望单个视图的旋转行为与堆栈中的其他视图的行为不同,则需要在根视图控制器中为其编写特定的大小写。
答案 3 :(得分:4)
我没有足够的声誉来评论@Brian的答案,所以我会在这里添加我的笔记。
Brian提到iOS6为rootViewController提供了旋转控件 - 这不仅可以是所提到的UINavigationController,还可以是UITabBarController,它适合我。我的结构看起来像这样:
所以我首先在自定义UITabBarController中添加方法,然后在自定义UINavigationController中添加,最后在特定的UIViewController中添加。
来自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];
}
答案 4 :(得分:3)
我想对我自己的问题给出部分答案。我发现在我的第三个viewWillAppear
的{{1}}方法中使用的以下代码行可以使用:
UIViewController
但我真的不喜欢这个解决方案。它使用技巧分配给只读属性,根据Apple文档,该属性表示设备的物理方向。这就像告诉iPhone跳到用户手中的正确方向。
我很想把它留在我的应用程序中,因为它只是起作用。但它感觉不对,所以我想提出一个清晰的解决方案。
答案 5 :(得分:1)
这是我用于ios 6.0中的方向支持
-(BOOL)shouldAutorotate{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
答案 6 :(得分:1)
因为这是一个受到高度关注的线程。我想我会加上我认为最简单的答案。这适用于ios8及以上
-(BOOL)shouldAutorotate
{
return YES;
}
和
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
就是这样。享受!
哦,我的ViewControllers嵌入在导航控制器中,我不需要以任何方式进行子类化或配置。
答案 7 :(得分:0)
你想强制推出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;
}
}
答案 8 :(得分:0)
这可能对每个人都不起作用,但对我来说效果很好。而不是实施......
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
在我所有控制器的viewWillAppear中,我决定通过覆盖UINavigationControllerDelegate方法navigationController:willShowViewController:animated:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
self.previousVCLandscapeOK = self.isLandscapeOK; // Store the current VC's orientation preference before pushing on the new VC so we can set this again from within the custom "back" method
self.isLandscapeOK = NO; // Set NO as default for all VC's
if ([viewController isKindOfClass:[YourViewController class]]) {
self.isLandscapeOK = YES;
}
}
我发现当从导航堆栈中弹出VC时,不会调用此委托方法。这对我来说不是问题,因为我正在处理我的UINavigationController子类中的后退功能,这样我就可以为特定的VC设置正确的导航栏按钮和操作......
if ([viewController isKindOfClass:[ShareViewController class]]) {
UIButton* backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 57, 30)];
[backButton setImage:[UIImage imageNamed:@"back-arrow"] forState:UIControlStateNormal];
[backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
viewController.navigationItem.leftBarButtonItem = backButtonItem;
UIImageView* shareTitle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"share-title"]];
[shareTitle setContentMode:UIViewContentModeScaleAspectFit];
[shareTitle setFrame:CGRectMake(0, 0, shareTitle.frame.size.width - 10, shareTitle.frame.size.height - 10)];
viewController.navigationItem.titleView = shareTitle;
} else if(...) {
...
}
以下是我的back
方法处理从堆栈中弹出VC并设置适当的旋转首选项...
- (void)back {
self.isLandscapeOK = self.previousVCLandscapeOK;
self.previousVCLandscapeOK = NO;
[self popViewControllerAnimated:YES];
}
所以,正如你所看到的,基本上所发生的一切都是我首先给我设置两个属性...
@property (nonatomic) BOOL isLandscapeOK;
@property (nonatomic) BOOL previousVCLandscapeOK;
navigationController:willShowViewController:animated:
中的将确定即将呈现的VC中支持的方向。当弹出VC时,我的自定义“后退”方法被调用,然后我将isLandscapeOK设置为通过previousVCLandscapeOK值存储的内容。
正如我所说的,这可能不适用于所有人,但它对我很有用,我不必担心为每个视图控制器添加代码,我能够将它全部集中在UINavigationController子类中
希望这可以帮助某人,因为它帮助了我。 谢谢,杰里米。
答案 9 :(得分:0)
转到Info.plist文件并进行更改
答案 10 :(得分:0)
除了一个外,我想让所有的VC锁定为纵向。这对我有用。
在根视图控制器中,检测窗口顶部的视图控制器的类型,并在 supportedInterfaceOrientations 方法中相应地设置应用程序的方向。例如,我只需要在webview位于堆栈顶部时旋转我的应用程序。这是我在rootVC中添加的内容:
-(NSUInteger)supportedInterfaceOrientations
{
UIViewController *topMostViewController = [[Utils getAppDelegate] appNavigationController].topViewController;
if ([topMostViewController isKindOfClass:[SVWebViewController class]]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
return UIInterfaceOrientationMaskPortrait;
}
答案 11 :(得分:0)
我没有足够的声誉来回答@micmdk回复下的@Ram S问题,所以我会在这里添加我的注释。
使用 UITabbarController 时,尝试更改 self.viewControllers.lastObject @ micmdk的 self.selectedViewController 的代码如下:
- (BOOL)shouldAutorotate {
return [self.selectedViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.selectedViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
答案 12 :(得分:0)
我已经解决了同样的问题。
如果您使用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
}
}
取代LoginViewController
使用您希望展示的UIViewController
。在我的情况下,我想在LoginViewController
模式中以Portrait
模式显示ViewControllers
landscape
{/ 1}}。
答案 13 :(得分:0)
您可以在所有View Controller类中实现和覆盖shouldAutorotate()和supportedInterfaceOrientations var,这些类应以与应用程序的PLIST中定义的方向不同的方向呈现。
但是,在一个非常重要的用户界面中,您可能会遇到一个问题,无法将其添加到几十个类中,并且您不希望将它们全部作为支持它的几个常见子类(MyBaseTableViewController,MyBaseNavigationController和MyBaseTabBarController)。
由于您无法直接在UIViewController上覆盖这些方法/ var,您可以在其子类上执行此操作,这些子类通常是您的基类,如UITableViewController,UINavigationController和UITabBarController。
所以你可以实现一些扩展,并且仍然设置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]
}
}
答案 14 :(得分:-1)
请使用以下方法解决此问题
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
只返回你想要的方向!!!