在 iOS 6 中没有调用 shouldAutorotateToInterfaceOrientation
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12260261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
shouldAutorotateToInterfaceOrientation not being called in iOS 6
提问by Hesham
I'm using MGSplitViewController and I'm usingshouldAutorotateToInterfaceOrientation
to control the size of the master view controller on rotation.
我正在使用 MGSplitViewController 并且我shouldAutorotateToInterfaceOrientation
用来控制旋转时主视图控制器的大小。
It's all working fine on iOS 5 but on iOS 6 (both simulator and iPad) shouldAutorotateToInterfaceOrientation
is never called.
在 iOS 5 上一切正常,但在 iOS 6(模拟器和 iPad)shouldAutorotateToInterfaceOrientation
上从未被调用。
Is this a bug that I should expect to be fixed with the final release of iOS 6 or something that I'm not aware of has changed?
这是一个我应该期望在 iOS 6 的最终版本中修复的错误还是我不知道的某些东西已经改变了?
回答by BootMaker
PLEASE READ this CAREFULLY or you could loose 1-2 days of your life with going nuts and fighting, shaking, turning your test device like the chimp in the zoo which grabbed a visitor's mobile! Sooner or later...promise :)
请仔细阅读本文,否则您可能会因为发疯、打架、摇晃、转动您的测试设备而失去生命的 1-2 天,就像动物园里的黑猩猩抓住游客的手机一样!迟早...承诺:)
IN iOS 6
在 iOS 6
shouldAutorotateToInterfaceOrientation:
is deprecated and replaced by
已弃用并替换为
shouldAutorotate
it means iOS 6 will never call shouldAutorotateToInterfaceOrientation
:
这意味着 iOS 6 永远不会调用shouldAutorotateToInterfaceOrientation
:
so if you used the following in your application
所以如果你在你的应用程序中使用了以下内容
BEFOREiOS6 (iOS5,iOS4 etc.)
iOS6之前(iOS5、iOS4 等)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode
}
return YES;
}
you should use
你应该使用
AFTERiOS 6+
在iOS 6+ 之后
- (BOOL)shouldAutorotate {
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode
}
return YES;
}
BE AWARE
意识到
UIInterfaceOrientation
is a property of UIApplication
and only contains 4 possibilities which correspond to the orientation of the status bar:
UIInterfaceOrientation
是一个属性UIApplication
并且只包含与状态栏方向相对应的 4 种可能性:
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
DO NOT CONFUSE IT WITH
不要将它与
UIDeviceOrientation
which is a property of the UIDevice
class, and contains 7 possible values:
UIDeviceOrientation
这是UIDevice
类的一个属性,包含 7 个可能的值:
UIDeviceOrientationUnknown - Can not be determined
UIDeviceOrientationPortrait - Home button facing down
UIDeviceOrientationPortraitUpsideDown - Home button facing up
UIDeviceOrientationLandscapeLeft - Home button facing right
UIDeviceOrientationLandscapeRight - Home button facing left
UIDeviceOrientationFaceUp - Device is flat, with screen facing up
UIDeviceOrientationFaceDown - Device is flat, with screen facing down
even you can theoretically use UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
which returns UIDeviceOrientation
- the device actual orientation - BUT you have to know that UIDeviceOrientation
is not always equal UIInterfaceOrientation
!!! For example, when your device is on a plain table you can receive unexpected value.
即使您理论上可以使用UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
which 返回UIDeviceOrientation
- 设备实际方向 - 但您必须知道这UIDeviceOrientation
并不总是相等UIInterfaceOrientation
!!!例如,当您的设备在普通桌子上时,您可能会收到意外的值。
You can use UIInterfaceOrientation orientation = self.interfaceOrientation;
too which returns UIInterfaceOrientation
, the current orientation of the interface, BUT it's a property of UIViewController
, so you can access to this one only in UIViewController
classes.
您也可以使用UIInterfaceOrientation orientation = self.interfaceOrientation;
which 返回UIInterfaceOrientation
,界面的当前方向,但它是 的属性UIViewController
,因此您只能在UIViewController
类中访问此属性。
If you'd like to support both prior iOS6 (iOS3/4/5) and iOS6 devices - which could be evident - just use both shouldAutorotateToInterfaceOrientation:
and shouldAutorotate
in your code.
如果您想同时支持之前的 iOS6 (iOS3/4/5) 和 iOS6 设备——这很明显——只需在代码中同时使用shouldAutorotateToInterfaceOrientation:
和shouldAutorotate
。
From iOS 6there are 3 levels and 3 steps which the device checks during app launch, which you have to control if you'd like.
从 iOS 6开始,设备在应用程序启动期间检查 3 个级别和 3 个步骤,如果您愿意,您必须控制这些步骤。
1. Info.plist - Supported Interface Orientations
which you could set graphically in the Summary tab. The sequence of allowed orientations is IMPORTANT, which you can change manually by editing the info.plist
, and the device will choose the first when the app is launching! This is critical as the problem always the launch of the app when there is the chance that the [UIDevice currentDevice].orientation
is unknown, especially when we test our app on a flat surface.
您可以在“摘要”选项卡中以图形方式设置。允许方向的顺序很重要,您可以通过编辑 手动更改info.plist
,当应用程序启动时,设备将选择第一个!这很关键,因为问题总是出现在有可能[UIDevice currentDevice].orientation
未知的情况下启动应用程序,尤其是当我们在平坦的表面上测试我们的应用程序时。
BE AWAREThere is two other settings possibility with (iPad) or (iPhone) extension, if you use any of them, it will use that setting of the current device or simulator and neglect the general settings without the extension. So if you run an iPhone only app and accidentally you left a "Supported Interface Orientations (iPad)" line somewhere in the plist even without any data, it will neglect the rules you have established earlier in the general settings (in my example for iPhone) and you could get a rejection for your App with a text "We found that your app did not meet the requirements for running on iPad..." even if your app doesn't intend to use a given orientation on iPhone, but iPad will use it which could cause unpredicted errors, as all iPhone apps have to run on iPad too during the submission process.
请注意(iPad) 或 (iPhone) 扩展程序还有另外两种设置可能性,如果您使用它们中的任何一个,它将使用当前设备或模拟器的设置,而忽略没有扩展程序的常规设置。因此,如果您运行仅适用于 iPhone 的应用程序,并且不小心在 plist 的某处留下了“支持的界面方向 (iPad)”行,即使没有任何数据,它也会忽略您之前在常规设置中建立的规则(在我的 iPhone 示例中) ) 并且您的应用程序可能会被拒绝并显示“我们发现您的应用程序不符合在 iPad 上运行的要求...”,即使您的应用程序不打算在 iPhone 上使用给定的方向,但在 iPad 上将使用它可能会导致不可预测的错误,
2. AppDelegate - application:supportedInterfaceOrientationsForWindow
returning a bit mask listing of every orientations you'd like to permit, which override the info.plist settings.This is called at least once every times the device rotates.
返回您想要允许的每个方向的位掩码列表,它覆盖 info.plist 设置。每次设备旋转时至少调用一次。
3. Top-level view controller or RootViewController - supportedInterfaceOrientations
which gives an intersection with the set of the app and app delegate, which has to have a non zero result to avoid crash. This is called at least once every times the device rotates, except there is an another method installed in our controller:
这给出了与应用程序和应用程序委托的集合的交集,它必须具有非零结果以避免崩溃。每次设备旋转时至少调用一次,除非我们的控制器中安装了另一种方法:
shouldAutorotate
which interferes with the app's permitted orientations, and gives a BOOL
with default YES
.
这会干扰应用程序允许的方向,并提供BOOL
默认的YES
.
BE CAREFUL when you use `NavigationController`
as the topmost controller in your AppDelegate
, like this:
作为 中最顶层的控制器AppDelegate
,如下所示:
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:detailViewController];
self.window.rootViewController =nil;
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
in this case you have to place the following code in your AppDelegate
as a category attachment to NavigationController
class, as this is the topmost controller, and if you haven't made a subcategory of it, you have no place/code where you can set its orientation settings, so you need to force it to check your real rootViewController
in this case the detailViewController
for the orientations:
在这种情况下,您必须将以下代码AppDelegate
作为类的类别附件放置在NavigationController
类中,因为这是最顶层的控制器,如果您还没有创建它的子类别,则没有可以设置其方向的位置/代码设置,因此您需要强制它rootViewController
在这种情况下检查您的真实detailViewController
方向:
@implementation UINavigationController (OrientationSettings_IOS6)
-(BOOL)shouldAutorotate {
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations {
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
@end
after this you can set the preferred orientations in your "topmost" ViewController
(in my example this is the detailViewController
) with any of the methods you have available in iOS 6 for ViewControllers
, as below:
在此之后,您可以使用 iOS 6 for 中可用的任何方法在“最顶层” ViewController
(在我的示例中是detailViewController
)中设置首选方向ViewControllers
,如下所示:
1. (BOOL)shouldAutorotate
2. (NSUInteger)supportedInterfaceOrientations
3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
回答by GeneCode
Ok, I got it to work in iOS6 iPad Simulator. Yay. Here's what I did:
好的,我让它在 iOS6 iPad Simulator 中工作。好极了。这是我所做的:
I just show you before and after, it should be self explanatory:
我只是在之前和之后向您展示,它应该是不言自明的:
BEFORE
前
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if (interfaceOrientation==UIInterfaceOrientationPortrait) {
// do some sh!t
}
return YES;
}
AFTER
后
- (BOOL)shouldAutorotate {
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation==UIInterfaceOrientationPortrait) {
// do some sh!t
}
return YES;
}
As for the supported orientation, you can either specify in info.plist as such:
至于支持的方向,您可以在 info.plist 中指定如下:
Or use code:
或使用代码:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait; // etc
}
Edit: On second thought, if you plan to support lower versions (iOS4.3/5/5.1) as well as 6.0 then just include both methods with the same code content. Works for me (in sim anyways)
编辑:再想一想,如果您计划支持较低版本(iOS4.3/5/5.1)以及 6.0,那么只需包含具有相同代码内容的两种方法。对我有用(无论如何都是在 sim 中)
回答by David Neil Wilson
Setting the app window route controller rather than, just adding it's view as a subview worked for me (as Rocotilos did)
设置应用程序窗口路由控制器,而不是将它的视图添加为对我有用的子视图(就像 Rocotilos 那样)
// [self.window addSubview:self.topLevelNavigationController.view];
self.window.rootViewController = self.topLevelNavigationController;
回答by user441669
Here's a solution for iOS 5 and earlier code that doesn't involve duplicating your logic. Simply add this code to your view controller and it generates the supportedInterfaceOrientations from your existing shouldAutorotateToInterfaceOrientation method.
这是适用于 iOS 5 和更早代码的解决方案,不涉及复制您的逻辑。只需将此代码添加到您的视图控制器,它就会从您现有的 shouldAutorotateToInterfaceOrientation 方法生成 supportedInterfaceOrientations。
-(BOOL)shouldAutorotate{
return YES;
}
-(NSInteger)supportedInterfaceOrientations{
NSInteger mask = 0;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight])
mask |= UIInterfaceOrientationMaskLandscapeRight;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeLeft])
mask |= UIInterfaceOrientationMaskLandscapeLeft;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortrait])
mask |= UIInterfaceOrientationMaskPortrait;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortraitUpsideDown])
mask |= UIInterfaceOrientationMaskPortraitUpsideDown;
return mask;
}
回答by g1de0n_ph
A quick fix for me was to add this code on my root view controller
对我来说一个快速的解决方法是在我的根视图控制器上添加这个代码
- (BOOL)shouldAutorotate {
return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}
This way I still use the same logic used for versions prior to iOS 6. Of course, I originally had set my rootViewController in my app delegates didFinishLaunchingWithOptions properly instead of just adding to the windows subviews.
这样我仍然使用用于 iOS 6 之前版本的相同逻辑。当然,我最初在我的应用程序委托中正确设置了我的 rootViewController didFinishLaunchingWithOptions 而不是仅仅添加到 windows 子视图。
回答by Christopher King
And while a number of the responses have the solution indicated -- that being to implement shouldAutorotate and supportedInterfaceOrientations for iOS 6 builds -- you should also be aware that if your view controller is hosted in a navigation controller then none of it will matter since the runtime will call these on the UINavigationController instance and ignore your code otherwise.
虽然许多响应都指出了解决方案——即为 iOS 6 构建实现 shouldAutorotate 和 supportedInterfaceOrientations——但您还应该意识到,如果您的视图控制器托管在导航控制器中,那么这一切都无关紧要,因为运行时将在 UINavigationController 实例上调用这些,否则忽略您的代码。
Apparently the 'solution' is to subclass UINavigationController and implement these new methods on this sub-class as described here: iOS 6 UITabBarController supported orientation with current UINavigation controller
显然,“解决方案”是继承 UINavigationController 并在此子类上实现这些新方法,如下所述: iOS 6 UITabBarController 支持当前 UINavigation 控制器的方向
And then you have the pleasure of changing all of your code where you use a UINavigationController to use this new sub-class instead.
然后你可以很高兴地更改所有使用 UINavigationController 的代码来使用这个新的子类。
This has to be one of the most pointless and annoying breaking-changes in an iOS release that I have ever seen.
这一定是我见过的 iOS 版本中最无意义和最烦人的重大更改之一。
回答by Roshan Jalgaonkar
IOS 5
IOS 5
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
if (UIInterfaceOrientationLandscapeLeft) {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
if (UIInterfaceOrientationLandscapeRight) {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
IOS 6
IOS 6
-(BOOL)shouldAutorotate{
return YES;
}
-(NSInteger)supportedInterfaceOrientations:(UIWindow *)window{
// UIInterfaceOrientationMaskLandscape;
// 24
//
// UIInterfaceOrientationMaskLandscapeLeft;
// 16
//
// UIInterfaceOrientationMaskLandscapeRight;
// 8
//
// UIInterfaceOrientationMaskPortrait;
// 2
// return UIInterfaceOrientationMaskLandscape;
return 24;
}
回答by Carlos Moura
This worked for me with iOS6 and Xcode 4.5 GM:
这适用于 iOS6 和 Xcode 4.5 GM:
On AppDelegate.m
在AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
.....
// self.window.rootViewController = self.navigationController;
[window setRootViewController:navigationController];
.....
return YES;
}
on ViewController:
在视图控制器上:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
// landscape
}
else
{
//portrait
}
}
回答by MkVal
Here's a quote from Apple's iOS SDK, XCode4.5+ (see UIViewController Class Reference, Handling View Rotations):
这里引用了 Apple 的 iOS SDK,XCode4.5+(请参阅 UIViewController 类参考,处理视图旋转):
In iOS 6, your app supports the interface orientations defined in your app's Info.plist file. A view controller can override the supportedInterfaceOrientationsmethod to limit the list of supported orientations. Generally, the system calls this method only on the root view controller of the windowor a view controller presented to fill the entire screen; child view controllers use the portion of the window provided for them by their parent view controller and no longer participate in directly in decisions about what rotations are supported.
在 iOS 6 中,您的应用支持在应用的 Info.plist 文件中定义的界面方向。视图控制器可以覆盖supportedInterfaceOrientations方法来限制支持的方向列表。一般情况下,系统只在窗口的根视图控制器或呈现为填满整个屏幕的视图控制器上调用该方法;子视图控制器使用父视图控制器为它们提供的窗口部分,不再直接参与决定支持哪些旋转。
Also in iOS6, shouldAutorotateToInterfaceOrientation:method of UIViewController class is already deprecated.
同样在 iOS6 中,shouldAutorotateToInterfaceOrientation :UIViewController 类的方法已经被弃用。
So in your root view controller, you do the ff:
因此,在您的根视图控制器中,您执行以下操作:
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
Btw, "root view controller" is any UIViewController subclass you set as the rootViewControllerof your appDelegate's windowobject. You usually do this in the appDelegate's application:didFinishLaunchingWithOptions:method.
顺便说一句,“根视图控制器”是您设置为appDelegate窗口对象的rootViewController的任何 UIViewController 子类。您通常在 appDelegate 的application:didFinishLaunchingWithOptions:方法中执行此操作。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.rootViewController = [FFDashboardController create];
[self.window makeKeyAndVisible];
return YES;
}
As to using UINavigationController as root VC's, checkout Vladimir's answer.
至于使用 UINavigationController 作为根 VC,请查看Vladimir 的回答。
回答by oddmeter
In response to @Rocotilos, I've got an addendum that occurred in my code that I've not seen elsewhere in the forums. I ran into a situation where at the very beginning of the app's life cycle, where the orientation was not known in the shouldAutorotate method. This was causing the app to not display the view properly in landscape. After a few rotations in the simulator it was working fine.
作为对@Rocotilos 的回应,我在我的代码中添加了一个我在论坛其他地方没有看到的附录。我遇到了一种情况,在应用程序生命周期的一开始,shouldAutorotate 方法中的方向未知。这导致应用程序无法在横向中正确显示视图。在模拟器中旋转几次后,它工作正常。
My scenario is that there are certain views that get popped on where we would want landscape layout. As such, we would not want shouldAutorotate to return YES. I realize this might be a rare case for some, but I've spent plenty of time diagnosing this and wanted to pass along. Hope this is helpful.
我的情况是,某些视图会弹出我们想要横向布局的位置。因此,我们不希望 shouldAutorotate 返回 YES。我意识到这对某些人来说可能是一种罕见的情况,但我已经花了很多时间来诊断这个问题,并希望传递下去。希望这是有帮助的。
- (BOOL) shouldAutorotate {
BOOL shouldRotate = NO;
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
if ([self IsCaseWhereWeDontWantLandscapeAutorotation]) {
shouldRotate = NO;
} else if (orientation == UIDeviceOrientationUnknown) {
//Handle the case where the device's orientation is not yet known
shouldRotate = YES;
} else {
//Handle the normal case
shouldRotate = (orientation == UIInterfaceOrientationMaskLandscape);
}
return shouldRotate;
}