57

我给了一个带有 10 个视图控制器的应用程序。我使用导航控制器来加载/卸载它们。

除了一个以外,其他所有人都处于纵向模式。假设第 7 个 VC 在横向。我需要它在加载时以横向呈现。

请建议一种在 IOS 6 中强制方向从纵向变为横向的方法(并且在 IOS 5 中也能很好地工作)。

这是我在IOS 6之前的做法:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    UIViewController *c = [[[UIViewController alloc]init] autorelease];
    [self presentModalViewController:c animated:NO];
    [self dismissModalViewControllerAnimated:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

呈现和关闭模态 VC 会迫使应用程序重新审视其方向,因此shouldAutorotateToInterfaceOrientation被调用。

我在 IOS 6 中尝试过的内容:

- (BOOL)shouldAutorotate{
    return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return UIInterfaceOrientationLandscapeLeft;
}

加载时,控制器保持纵向。旋转设备后,方向改变就好了。但我需要让控制器在加载时自动旋转为横向,因此用户必须旋转设备才能正确查看数据。

另一个问题:将设备旋转回纵向后,方向变为纵向,尽管我supportedInterfaceOrientations仅在UIInterfaceOrientationMaskLandscape. 为什么会发生?

此外,以上3 种方法都没有被调用。

一些(有用的)数据:

  1. 在我的 plist 文件中,我指定了 3 个方向 - 几乎都是颠倒的。
  2. 该项目是在 Xcode 4.3 IOS 5 开始的。包括 xibs 在内的所有类都是在 Xcode 4.5 IOS 6 之前创建的,现在我使用最后一个版本。
  3. 在 plist 文件中,状态栏设置为可见。
  4. 在 xib 文件(我想要横向的文件)中,状态栏为“无”,方向设置为横向。

任何帮助表示赞赏。谢谢。

4

13 回答 13

43

好的,伙计们,我将发布我的解决方案。

是)我有的:

  1. 基于视图的应用程序,具有多个视图控制器。(它是基于导航的,但由于方向问题,我不得不使其基于视图)。
  2. 所有视图控制器都是纵向的,除了一个 - LandscapeLeft。

任务:

  1. 无论用户如何握住设备,我的视图控制器之一都必须自动旋转到横向。所有其他控制器必须是纵向的,并且在离开横向控制器后,应用程序必须强制旋转到纵向,无论用户如何握住设备。
  2. 这必须像在 IOS 6.x 上一样在 IOS 5.x 上工作

去!

更新删除了@Ivan Vučica 建议的宏)

在您的所有 PORTRAIT 视图控制器中,都会覆盖这样的自动旋转方法:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

您可以看到 2 种方法:一种用于 IOS 5,另一种用于 IOS 6。

您的 LANDSCAPE 视图控制器也是如此,但有一些添加和更改:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    [image_signature setImage:[self resizeImage:image_signature.image]];
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    [image_signature setImage:[self resizeImage:image_signature.image]];
    return UIInterfaceOrientationMaskLandscapeLeft;
}

注意:要在IOS 5中强制自动旋转,您应该添加以下内容:

- (void)viewDidLoad{
    [super viewDidLoad];
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
        [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];    
}

类似地,在您离开 LANDSCAPE 控制器后,无论您加载什么控制器,您都应该再次强制 IOS 5 自动旋转,但现在您将使用UIDeviceOrientationPortrait,当您转到 PORTRAIT 控制器时:

- (void)viewDidLoad{
        [super viewDidLoad];
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
            [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];    
    }

现在是最后一件事(这有点奇怪) - 您必须根据 IOS 更改从控制器切换到另一个控制器的方式:

制作一个 NSObject 类“Schalter”(德语中的“Switch”)。

在 Schalter.h 中说:

#import <Foundation/Foundation.h>

@interface Schalter : NSObject
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease;
@end

在 Schalter.m 中说:

#import "Schalter.h"
#import "AppDelegate.h"

@implementation Schalter
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease{

    //adjust the frame of the new controller
    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
    CGRect windowFrame = [[UIScreen mainScreen] bounds];
    CGRect firstViewFrame = CGRectMake(statusBarFrame.origin.x, statusBarFrame.size.height, windowFrame.size.width, windowFrame.size.height - statusBarFrame.size.height);
    VControllerToLoad.view.frame = firstViewFrame;

    //check version and go
    if (IOS_OLDER_THAN_6)
        [((AppDelegate*)[UIApplication sharedApplication].delegate).window addSubview:VControllerToLoad.view];
    else
        [((AppDelegate*)[UIApplication sharedApplication].delegate).window setRootViewController:VControllerToLoad];

    //kill the previous view controller
    [VControllerToRelease.view removeFromSuperview];
}
@end

现在,这就是您使用 Schalter 的方式(假设您从 Warehouse 控制器转到 Products 控制器):

#import "Warehouse.h"
#import "Products.h"

@implementation Warehouse
Products *instance_to_products;

- (void)goToProducts{
    instance_to_products = [[Products alloc] init];
    [Schalter loadController:instance_to_products andRelease:self];
}

bla-bla-bla your methods

@end

当然你必须释放instance_to_products对象:

- (void)dealloc{
     [instance_to_products release];
     [super dealloc];
}

嗯,就是这样。不要犹豫投反对票,我不在乎。这是给那些正在寻找解决方案的人,而不是为了声誉。干杯! 萨瓦马扎雷。

于 2012-10-04T11:00:30.227 回答
34

这应该可以工作,它类似于 iOS 6 之前的版本,但带有UINavigationController

UIViewController *portraitViewController = [[UIViewController alloc] init];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController];
[self.navigationController presentModalViewController:nc animated:NO];
[self.navigationController dismissModalViewControllerAnimated:NO];

在我推动下一个之前,我会打电话给这个UIViewControllerUIViewController即使当前处于横向模式,它也会强制下一个推送以纵向模式显示UIViewController(也应该适用于纵向到横向)。适用于我的 iOS 4+5+6。

于 2012-10-01T15:14:22.533 回答
14

我认为最好的解决方案是坚持苹果官方文档。因此,据此,我使用以下方法,并且在 iOS 5 和 6 上一切正常。在我的 VC 中,我覆盖了以下方法:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

iOS 6 的方法,第一个方法返回支持的方向掩码(如其名称所示)

-(NSUInteger)supportedInterfaceOrientations{

    return UIInterfaceOrientationMaskPortrait;
}

第二个就是告诉您的 VC,当 VC 将要显示时,哪个是首选界面方向。

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

只需将 Portrait 更改为您想要的方向 ;) 这个解决方案运行顺利,我不喜欢创建宏和其他东西的想法,围绕这个简单的解决方案。希望这有助于...

于 2012-11-13T11:39:47.833 回答
7

我遇到了同样的问题,我的应用程序中有 27 个视图,其中 26 个是纵向视图,而所有方向只有一个(图像查看器 :))。在每个类上添加宏并替换导航并不是我喜欢的解决方案......

所以,我想在我的应用程序中保留 UINavigationController 机制,而不是用其他代码替换它。

该怎么办:

@1 在方法 didFinishLaunchingWithOptions 中的应用程序委托中

if ([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
    // how the view was configured before IOS6
    [self.window addSubview: navigationController.view];
    [self.window makeKeyAndVisible];
}
else
{
    // this is the code that will start the interface to rotate once again
    [self.window setRootViewController: self.navigationController];
}

@2 因为navigationController 只会以YES 响应自动旋转,所以我们需要添加一些限制:扩展UINavigationController -> YourNavigationController 并将其链接到Interface Builder。

@3 覆盖导航控制器中的“讨厌的新方法”。

由于此类仅针对此应用程序是自定义的,因此它可以对其控制器负责并在其位置做出响应。

-(BOOL)shouldAutorotate {

    if ([self.viewControllers firstObject] == YourObject)
    {
         return YES;
    }
    return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
     if ([self.viewControllers firstObject] == YourObject)
    {
         return UIINterfaceOrientationMaskLandscape;
    }
    return UIInterfaceOrientationMaskPortrait;
}

我希望这能帮到您,

于 2012-10-14T23:47:26.560 回答
3

iOS 6 发行说明

现在,iOS 容器(例如 UINavigationController)不会咨询它们的子容器来确定它们是否应该自动旋转。

您是否将消息向下rootViewController传递给您的 VC?shouldAutoRotateViewController

于 2012-09-28T13:55:08.750 回答
2

我使用与 OP pre-ios6 相同的方法(呈现和关闭模态 VC)以横向模式显示单个视图控制器(所有其他视图控制器以纵向模式)。它在 ios6 中中断,横向 VC 以纵向显示。

为了解决这个问题,我刚刚在景观 VC 中添加了 preferredInterfaceOrientationForPresentation 方法。现在似乎适用于 os 5 和 os 6。

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

- (BOOL)shouldAutorotate
{
return NO;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{    
return UIInterfaceOrientationLandscapeLeft;
}
于 2013-02-20T02:08:05.430 回答
2

嘿伙计们,在尝试了很多不同的可能解决方案但没有成功后,我提出了以下解决方案,希望对您有所帮助!

我准备了一个食谱:)。

问题: 您需要在 ios 6 中使用导航控制器更改视图控制器的方向。

解决方案:

建议导航

步骤 1.一个初始 UIviewcontroler 触发模式 segues 到横向和纵向 UInavigationControllers 如图所示....

在 UIViewController1 中更深入,我们需要根据 Appdelegate 处的全局变量进行 2 次 segues 操作....

-(void)viewDidAppear:(BOOL)animated{
    if([globalDelegate changeOrientation]==0){
        [self performSegueWithIdentifier:@"p" sender:self];
    }
    else{
        [self performSegueWithIdentifier:@"l" sender:self];
    }

}

我们还需要回到肖像&| 景观....

- (IBAction)dimis:(id)sender {
    [globalDelegate setChangeOrientation:0];
    [self dismissViewControllerAnimated:NO completion:nil];
}

步骤 2.每个 NavigationController 上的第一个 Pushed UiViewControllers 与...

-(NSUInteger)supportedInterfaceOrientations{
    return [self.navigationController supportedInterfaceOrientations];
}

-(BOOL)shouldAutorotate{
    return YES;
}

步骤 3.我们在 UInavigationController 的子类中覆盖 supportedInterfaceOrientations 方法......

在您的 customNavigationController 我们有.....

-(NSUInteger)supportedInterfaceOrientations{
    if([self.visibleViewController isKindOfClass:[ViewController2 class]]){

        return UIInterfaceOrientationMaskPortrait;
    }
    else{
        return UIInterfaceOrientationMaskLandscape;

    }

}

步骤 4.在情节提要或通过代码,将 WantsFullScreenLayout 标志设置为 yes,同时设置为纵向和横向 uinavigationcontrollers。

于 2013-03-07T22:48:04.450 回答
1

尝试转到UINavigationController使用类别或子类以指定所需方向的 a,然后转到所需的 VC。在这里阅读更多。

于 2012-09-28T14:03:29.050 回答
1

作为替代方案,您可以使用块执行相同的操作:

UIViewController *viewController    = [[UIViewController alloc] init];
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:viewController animated:NO completion:^{
    [self dismissViewControllerAnimated:NO completion:nil];
}];

另外,在推送新视图之前调用它。

于 2013-11-12T02:20:19.237 回答
0

转到您的 Info.plist 文件并进行更改在此处输入图像描述

于 2013-08-02T21:59:14.277 回答
0

我有同样的问题。如果您想强制特定视图控制器以横向显示,请在将其推送到导航堆栈之前立即执行此操作。

UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        if (currentOrientation == UIInterfaceOrientationPortrait ||
            currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
            [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];

        UIViewController *vc = [[UIViewController alloc] init];
        [self.navigationController pushViewController:vc animated:YES];
        [vc release];
于 2013-09-17T11:27:39.167 回答
0

我通过继承 UINavigationController 并覆盖导航控制器的 supportedInterfaceOrientations 来解决它,如下所示:

- (NSUInteger)supportedInterfaceOrientations
{
     return [[self topViewController] supportedInterfaceOrientations];
}

所有控制器都实现了带有所需方向的supportedInterfaceOrientations。

于 2014-02-14T23:08:11.697 回答
-1

我使用了以下解决方案。在一个方向与其他视图控制器不同的视图控制器中,我在prepareForSegue方法中添加了方向检查。如果目标视图控制器需要与当前显示的界面方向不同的界面方向,则会发送一条消息,强制界面在序列期间旋转。

#import <objc/message.h>

...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if(UIDeviceOrientationIsLandscape(self.interfaceOrientation))
    {
        UIInterfaceOrientation destinationOrientation;

        if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]])
        {
            UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
            destinationOrientation = [navController.topViewController preferredInterfaceOrientationForPresentation];
        } else
        {
            destinationOrientation = [[segue destinationViewController] preferredInterfaceOrientationForPresentation];
        }

        if ( destinationOrientation == UIInterfaceOrientationPortrait )
        {
            if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
            {
                objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), UIInterfaceOrientationPortrait );
            }
        }
    }
}
于 2013-07-11T17:01:20.173 回答