简体   繁体   English

iOS 6迫使设备朝向横向

[英]IOS 6 force device orientation to landscape

I gave an app with say 10 view controllers. 我给了一个带有10个视图控制器的应用程序。 I use navigation controller to load/unload them. 我使用导航控制器加载/卸载它们。

All but one are in portrait mode. 除了一个以外,其他所有设备都处于纵向模式。 Suppose the 7th VC is in landscape. 假设第7个VC处于横向状态。 I need it to be presented in landscape when it gets loaded. 我需要在加载时以横向显示它。

Please suggest a way to force the orientation go from portrait to landscape in IOS 6 (and it will be good to work in IOS 5 as well). 请提出一种在IOS 6中强制将方向从纵向更改为横向的方法 (在IOS 5中也同样适用)。

Here is how I was doing it BEFORE IOS 6: 这是我 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);
}

Presenting and dismissing a modal VC was forcing the app to review its orientation, so shouldAutorotateToInterfaceOrientation was getting called. 呈现和消除模态VC迫使该应用检查其方向,因此应该调用shouldAutorotateToInterfaceOrientation

What I have have tried in IOS 6: 我在IOS 6中尝试过的方法:

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

On load, the controller keeps staying in portrait. 加载时,控制器保持纵向状态。 After rotating the device, the orientation changes just ok. 旋转设备后,方向更改就可以了。 But I need to make the controller to rotate automatically to landscape on load, thus the user will have to rotate the device to see the data correctly. 但是我需要使控制器自动旋转以在负载时横向显示,因此用户将不得不旋转设备才能正确查看数据。

Another problem: after rotating the device back to portrait, the orientation goes to portrait, although I have specified in supportedInterfaceOrientations only UIInterfaceOrientationMaskLandscape . 另一个问题:将设备旋转回纵向后,方向变为纵向,尽管我在supportedInterfaceOrientations仅指定了UIInterfaceOrientationMaskLandscape Why it happens? 为什么会发生?

Also, NONE of above 3 methods are getting called. 另外,以上3种方法都不是获取调用。

Some (useful) data: 一些(有用的)数据:

  1. In my plist file I have specified 3 orientations - all but upside down. 在我的plist文件中,我指定了3个方向-除了上下颠倒外,其他所有方向。
  2. The project was started in Xcode 4.3 IOS 5. All classes including xibs were created before Xcode 4.5 IOS 6, now I use the last version. 该项目是从Xcode 4.3 IOS 5开始的。包括xibs在内的所有类都是在Xcode 4.5 IOS 6之前创建的,现在我使用的是最新版本。
  3. In plist file the status bar is set to visible. 在plist文件中,状态栏设置为可见。
  4. In xib file (the one I want to be in landscape) the status bar is "None", the orientation is set to landscape. 在xib文件中(我要在横向文件中),状态栏为“无”,方向设置为横向。

Any help is appreciated. 任何帮助表示赞赏。 Thanks. 谢谢。

Ok, folks, I will post my solution. 好的,伙计们,我将发布解决方案。

What I have: 是)我有的:

  1. A view based application, with several view controllers. 基于视图的应用程序,带有多个视图控制器。 (It was navigation based, but I had to make it view based, due to orientation issues). (它是基于导航的,但是由于方向问题,我不得不使其基于视图)。
  2. All view controllers are portrait, except one - landscapeLeft. 除了一个-landscapeLeft,所有的视图控制器都是纵向的。

Tasks: 任务:

  1. One of my view controllers must automatically rotate to landscape, no matter how the user holds the device. 无论用户如何握住设备,我的视图控制器之一都必须自动旋转到横向。 All other controllers must be portrait, and after leaving the landscape controller, the app must force rotate to portrait, no matter, again, how the user holds the device. 所有其他控制器都必须是纵向的,并且离开横向控制器后,应用程序必须强制旋转为纵向,无论用户如何握住设备。
  2. This must work as on IOS 6.x as on IOS 5.x 这必须与IOS 5.x一样在IOS 6.x上工作

Go! 走!

( Update Removed the macros suggested by @Ivan Vučica) 更新删除了@IvanVučica建议的宏)

In all your PORTRAIT view controllers override autorotation methods like this: 在您所有的PORTRAIT视图控制器中,都将覆盖如下的自动旋转方法:

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

You can see the 2 approaches: one for IOS 5 and another For IOS 6. 您可以看到两种方法:一种用于IOS 5,另一种用于IOS 6。

The same for your LANDSCAPE view controller, with some additions and changes: 对于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;
}

ATTENTION : to force autorotation in IOS 5 you should add this: 注意 :要在IOS 5中强制自动旋转,您应该添加以下内容:

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

Analogically, after you leave the LANDSCAPE controller, whatever controller you load, you should force again autorotation for IOS 5, but now you will use UIDeviceOrientationPortrait , as you go to a PORTRAIT controller: 类似地,离开LANDSCAPE控制器后,无论加载了什么控制器,都应再次强制IOS 5自动旋转,但是现在您将使用UIDeviceOrientationPortrait ,然后转到PORTRAIT控制器:

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

Now the last thing (and it's a bit weird) - you have to change the way you switch from a controller to another, depending on the IOS: 现在最后一件事(有点奇怪)-您必须根据IOS更改从控制器切换到另一个控制器的方式:

Make an NSObject class "Schalter" ("Switch" from German). 创建一个NSObject类“ Schalter”(德语为“ Switch”)。

In Schalter.h say: 在Schalter.h中说:

#import <Foundation/Foundation.h>

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

In Schalter.m say: 在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

NOW, this is the way you use Schalter ( suppose you go from Warehouse controller to Products controller ) : 现在,这就是您使用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

Of course you must release instance_to_products object: 当然,您必须释放instance_to_products对象:

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

Well, this is it. 好吧,就是这样。 Don't hesitate to downvote, I don't care. 不要犹豫,我不在乎。 This is for the ones who are looking for solutions, not for reputation. 这是针对那些寻求解决方案而不是声誉的人。 Cheers! 干杯! Sava Mazare. 萨瓦·马扎雷(Sava Mazare)。

This should work, it's similar to the pre-iOS 6 version, but with a UINavigationController : 这应该可以工作,类似于iOS 6之前的版本,但是带有UINavigationController

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

I'm calling this before I'm pushing the next UIViewController . 在推送下一个UIViewController之前,我先打电话给我。 It will force the next pushed UIViewController to be displayed in Portrait mode even if the current UIViewController is in Landscape (should work for Portrait to Landscape too). 即使当前的UIViewController处于“横向”状态,它也会强制下一个推送的UIViewController以“纵向”模式显示(也适用于“纵向至横向”)。 Works on iOS 4+5+6 for me. 适用于iOS 4 + 5 + 6。

I think that best solution is to stick to official apple documentation. 我认为最好的解决方案是坚持使用Apple官方文档。 So according to that I use following methods and everything is working very well on iOS 5 and 6. In my VC I override following methods: 因此,据此我使用以下方法,并且在iOS 5和6上一切正常。在我的VC中,我重写了以下方法:

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

Methods for iOS 6, first method returns supported orientation mask (as their name indicate) 适用于iOS 6的方法,第一种方法返回支持的方向遮罩(如其名称所示)

-(NSUInteger)supportedInterfaceOrientations{

    return UIInterfaceOrientationMaskPortrait;
}

second one thats tells your VC which is preferred interface orientation when VC is going to be displayed. 第二个告诉您的VC,当要显示VC时,这是首选的界面方向。

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

Just change Portrait for orientation that you want ;) This solution is working smooth, I don't like the idea of creating macros and other stuff, that goes around this simple solution. 只需将Portrait更改为所需的方向即可;)此解决方案运行流畅,我不喜欢围绕此简单解决方案创建宏和其他内容的想法。 Hope this help... 希望能有所帮助...

I had the same problem, 27 views in my application from which 26 in portrait and only one in all orientations ( an image viewer :) ). 我遇到了同样的问题,我的应用程序中有27个视图,其中26个是纵向视图,而所有方向都只有一个(图像查看器:))。 Adding the macro on every class and replace the navigation wasn't a solution I was comfortable with... 在每个类上添加宏并替换导航不是我满意的解决方案...

So, i wanted to keep the UINavigationController mechanics in my app and not replace this with other code. 因此,我想将UINavigationController机制保留在我的应用程序中,而不是用其他代码替换。

What to do: 该怎么办:

@1 In the application delegate in method didFinishLaunchingWithOptions @ 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 Because the navigationController will just responde with YES for autorotation we need to add some limitations: Extend the UINavicationController -> YourNavigationController and link it in the Interface Builder. @ 2因为navigationController只会对YES进行自动旋转,所以我们需要添加一些限制:扩展UINavicationController-> YourNavigationController并将其链接到Interface Builder中。

@3 Override the "anoying new methods" from navigation controller. @ 3覆盖导航控制器中的“正在使用新方法”。

Since this class is custom only for this application it can take responsibility for it's controllers and respond in their place. 由于此类仅针对此应用程序是自定义的,因此它可以对其控制器负责并在其位置进行响应。

-(BOOL)shouldAutorotate {

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

I hope this will help you, 我希望这能帮到您,

From the iOS 6 Release Notes : iOS 6发行说明中

Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate. 现在,iOS容器(例如UINavigationController)不再咨询其子级以确定它们是否应该自动旋转。

Does your rootViewController pass the shouldAutoRotate message down the ViewController hierarchy to your VC? 请问您rootViewController传递shouldAutoRotate消息下来ViewController层次到你的VC?

I used the same method as OP pre-ios6 (present and dismiss a modal VC) to show a single view controller in landscape mode (all others in portrait). 我使用了与OP pre-ios6相同的方法(显示和关闭模态VC)以横向模式显示单个视图控制器(所有其他模式为纵向)。 It broke in ios6 with the landscape VC showing in portrait. 它在ios6中中断,横向VC显示为纵向。

To fix it, I just added the preferredInterfaceOrientationForPresentation method in the landscape VC. 要解决此问题,我只在横向VC中添加了preferredInterfaceOrientationForPresentation方法。 Seems to work fine for os 5 and os 6 now. 似乎现在适用于os 5和os 6。

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

- (BOOL)shouldAutorotate
{
return NO;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{    
return UIInterfaceOrientationLandscapeLeft;
}

Hey guys after tryng a lot of different possible solutions with no success i came out with the following solution hope it helps!. 大家尝试了许多不同的解决方案但没有成功后,我提出了以下解决方案,希望对您有所帮助!

I prepared a recipe :). 我准备了一个食谱:)。

Problem: you need change orientation of viewcontrollers using navigationcontroller in ios 6. 问题:您需要在iOS 6中使用Navigationcontroller更改ViewController的方向。

Solution: 解:

导航建议

step 1. one initial UIviewcontroler to trigger modal segues to landscape and portrait UInavigationControllers as picture shows.... 步骤1.如图所示,一个初始UIviewcontroler触发横向和纵向UInavigationControllers的模式选择。

more deeply in UIViewController1 we need 2 segues actions according to global variable at Appdelegate.... 在UIViewController1中,我们需要根据Appdelegate的全局变量执行2个segues操作。

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

}

also we need a way back to portrait &| 我们还需要一种返回肖像&|的方式 landscape.... 景观....

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

step 2. the first Pushed UiViewControllers at each NavigationController goes with... 步骤2.每个NavigationController的第一个Pushed UiViewControllers都与...

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

-(BOOL)shouldAutorotate{
    return YES;
}

step 3. We overwrite supportedInterfaceOrientations method at subclass of UInavigationController.... 第3步。我们覆盖UInavigationController子类中的supportedInterfaceOrientations方法。

in your customNavigationController we have ..... 在您的customNavigationController中,我们有.....

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

        return UIInterfaceOrientationMaskPortrait;
    }
    else{
        return UIInterfaceOrientationMaskLandscape;

    }

}

step 4. At storyboard or by code, set wantsFullScreenLayout flag to yes, to both portrait and landscape uinavigationcontrollers. 第4步。在情节提要或通过代码将肖像和风景uinavigationcontrollers的wantsFullScreenLayout标志设置为yes。

Try segueing to a UINavigationController which uses a category or is subclassed to specify the desired orientation, then segue to the desired VC. 尝试选择使用类别或子类化的UINavigationController来指定所需的方向,然后选择所需的VC。 Read more here . 在这里阅读更多。

As an alternative you can do the same using blocks: 或者,您可以使用块来执行相同的操作:

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

Also, call it before pushing the new view. 另外,在推送新视图之前先调用它。

Go to you Info.plist file and make the change 转到您的Info.plist文件并进行更改 在此处输入图片说明

I had the same problem. 我有同样的问题。 If you want to force a particular view controller to appear in landscape, do it right before you push it into the navigation stack. 如果要强制特定的视图控制器以横向显示,请在将其推入导航堆栈之前立即进行操作。

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

I solved it by subclassing UINavigationController and overriding the supportedInterfaceOrientations of the navigation Controller as follow: 我通过子类化UINavigationController并重写导航控制器的supportedInterfaceOrientations来解决此问题,如下所示:

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

All the controllers implemented supportedInterfaceOrientations with their desired orientations. 所有控制器都以所需的方向实现了supportInterfaceOrientations。

I have used the following solution. 我已经使用以下解决方案。 In the one view controller that has a different orientation than all the others, I added an orientation check in the prepareForSegue method. 在一个方向与所有其他方向都不相同的视图控制器中,我在prepareForSegue方法中添加了方向检查。 If the destination view controller needs a different interface orientation than the current one displayed, then a message is sent that forces the interface to rotate during the seque. 如果目标视图控制器需要的界面方向与当前显示的界面方向不同,则会发送一条消息,迫使界面在定序期间旋转。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM