IOS 6强制设备方向为横向

Posted

技术标签:

【中文标题】IOS 6强制设备方向为横向【英文标题】:IOS 6 force device orientation to landscape 【发布时间】: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 被调用。

一些(有用的)数据:

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

感谢任何帮助。谢谢。

【问题讨论】:

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

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

我有什么:

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

任务:

    无论用户如何握住设备,我的一个视图控制器都必须自动旋转到横向。所有其他控制器必须是纵向的,并且在离开横向控制器后,应用必须强制旋转到纵向,无论用户如何握住设备。 这必须在 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 永远不是解决方案。

以上是关于IOS 6强制设备方向为横向的主要内容,如果未能解决你的问题,请参考以下文章

在一个模式视图控制器上强制 iOS 方向为横向

如何在 React Native 中根据设备类型设置强制设备方向?

AS3 - 仅 iOS 强制横向模式?

在iOS中单击按钮将设备方向从纵向更改为横向

强制“横向”定向模式

在 Objective-C 中的 iOS 6 上强制横向方向