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强制设备方向为横向的主要内容,如果未能解决你的问题,请参考以下文章