【问题标题】:IOS 6 force device orientation to landscapeIOS 6强制设备方向为横向
【发布时间】:2012-09-28 13:22:00
【问题描述】:

我给了一个带有 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 个方法中的 NONE 被调用。

一些(有用的)数据:

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

感谢任何帮助。谢谢。

【问题讨论】:

  • 我有同样的问题,你解决了吗?
  • 我讨厌新的 ios 6。我必须更改所有应用程序才能使方向正常工作。
  • yop, @bagusflyer, das ist da life of da 程序员)))
  • 这个问题就像我的问题,我解决了。解决方案:stackoverflow.com/questions/14658268/…
  • 您的问题对我来说是一个解决方案。我也想要同样的,我刚刚写了你的 ios6 代码,它对我有用。它会自动为我加载横向视图。

标签: iphone objective-c orientation ios6


【解决方案1】:

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

我有什么:

  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;
}

您可以看到两种方法:一种适用于 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];
}

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

【讨论】:

  • 那些#ifdef IOS_OLDER_THAN_6 行没有做任何事情,因为您显然无条件地定义了宏。即使他们这样做了,他们也会进行编译时检查。您以后可以使用这些宏。
  • 当然他们什么都不做,他们不应该做。它们只被声明,然后,在编译时,它们的值被设置为常规代码
  • Sava,我明白你为什么 #define 他们以及为什么你以后使用它们,这很正常 :-) 但我不明白你为什么要检查它们是否是使用 #ifdef 定义的。您的第二个和第三个代码块不需要#ifdef 检查:-)
  • 这些宏(例如IOS_OLDER_THAN_6)不应该用于检查iOS版本。 systemVersion 不是浮点值(例如 5.1.1 不是浮点数),它实际上有时会导致错误的结果。 See here for the correct way of doing this
  • [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];我也在 iOS 6 上尝试过这个并且它有效。我不必做你有线的事情:) 你怎么看?请指教。顺便说一句,我的情况与您在下面的答案中详细解释的情况完全相同。
【解决方案2】:

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

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

在我推送下一个UIViewController 之前,我会调用它。它会强制下一个推送的UIViewController 以纵向模式显示,即使当前UIViewController 处于横向模式(也适用于纵向到横向)。对我来说适用于 iOS 4+5+6。

【讨论】:

  • 不是,@Chunkylover53,接受的答案是我找到的最接近解决方案的答案。我会尽快发布。
  • 老兄,你太棒了)))我在发布我的解决方案后很久就尝试了你的提示,它确实有效。我没有正确理解你。我已经回到导航基地。我会尽快发布解决方案
  • 你能详细说明什么时候应该使用它吗?我遇到了同样的问题,当我的其余视图控制器是纵向时,我需要下一个推送的视图控制器处于横向。我正在使用 UINavigationController,但不确定该代码应该放在哪里。在推送横向视图控制器之前,我尝试使用此代码,但没有成功
  • 此解决方法也适用于非导航控制器应用程序。我只是使用我的 rootViewController 来呈现模态 UIViewController,主要的好处是调用了“preferredInterfaceOrientationForPresentation”。在这种方法中,我使用“UIDeviceOrientation”来检测方向设备有什么。奇迹般有效! :)
  • 但是当我dismissModalViewController时我遇到了一些问题然后我的所有用户界面都受到干扰。这个问题只在iOS 6中
【解决方案3】:

我认为最好的解决方案是坚持苹果官方文档。因此,据此,我使用以下方法,并且在 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;
}

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

【讨论】:

    【解决方案4】:

    我遇到了同样的问题,我的应用程序中有 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;
    }
    

    希望对你有帮助

    【讨论】:

    • 谢谢,setRootViewController 解决了我遇到的问题!
    • 我有点困惑:[self.viewControllers firstObject] 因为 NSArray 没有名为 'firstObject' 的方法,无论如何不确定你是否想要查看列表中的第一个对象视图控制器。也许你的意思是 self.topViewController?
    • UIViewController* vc = (UIViewController*)[self.viewControllers lastObject]; if ([NSStringFromClass([vc class]) isEqualToString:@"YourControllerClassName"]) { return UIInterfaceOrientationMaskAll;返回 UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
    【解决方案5】:

    来自iOS 6 Release Notes

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

    您的rootViewController 是否将shouldAutoRotate 消息沿ViewController 层次结构传递给您的VC?

    【讨论】:

    • 嗯...传递 shouldAutoRotate 是什么意思?在 applicationDidFinishLaunching 我说 [self.window setRootViewController:navigationController] (navigationController 是 AppDelegate 中 UINavigationController 的一个实例)
    • 如上述发行说明中所述,仅询问rootViewController 哪些方向有效。如果您的横向视图控制器不是rootViewController,那么它不会被询问 - UINavigationController 只会返回它认为有效的任何方向。
    • 但是如果它不应该成为 root,我怎么能使它成为 root - 它是(比如说)导航控制器堆栈中的第 7 个。
    • 谢谢!我做到了。有点不同,但您的建议会导致正确的方法
    • 查看解决方案,@sjwarner,我已发布为“回答自己的问题”
    【解决方案6】:

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

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

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

    【讨论】:

    • 这是我找到的有关此问题的唯一不令人困惑的答案。
    【解决方案7】:

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

    我准备了一个食谱:)。

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

    解决方案:

    第 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。

    【讨论】:

      【解决方案8】:

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

      【讨论】:

        【解决方案9】:

        您也可以使用块来做同样的事情:

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

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

        【讨论】:

          【解决方案10】:

          转到您的 Info.plist 文件并进行更改

          【讨论】:

            【解决方案11】:

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

            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];
            

            【讨论】:

            • ` [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];` 不适用于 iOS 6
            【解决方案12】:

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

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

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

            【讨论】:

              【解决方案13】:

              我使用了以下解决方案。在一个方向与其他视图控制器不同的视图控制器中,我在 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 );
                          }
                      }
                  }
              }
              

              【讨论】:

              • 使用私有 API 永远不是解决方案。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-02-08
              相关资源
              最近更新 更多