iOS 6:如何限制一些视图的肖像,并允许他人旋转?
我有一个iPhone应用程序,它使用UINavigationController
来呈现一个向下钻取的界面:第一个视图,然后是另一个视图,深达四层。 我希望将前三个视图限制为纵向,只允许最后一个视图旋转到横向。 当从第四个视图返回到第三个视图,并且第四个视图处于横向时,我希望所有的东西都旋转回肖像。
在iOS 5中,我简单地定义了shouldAutorotateToInterfaceOrientation:
在我的每个视图控制器中为允许的方向返回YES。 一切工作如上所述,包括即使从视图控制器#4到#3返回时横向保持设备也返回肖像。
在iOS 6中,所有的视图控制器旋转到横向,打破那些不意味着。 iOS 6发行说明说
更多的责任是转移到应用程序和应用程序委托。 现在,iOS容器(如
UINavigationController
)不会咨询他们的孩子,以确定他们是否应该自动旋转。 […]系统每当设备旋转时或每当视图控制器呈现全屏模式演示风格时,都会询问其支持的接口方向的最顶级全屏视图控制器(通常是根视图控制器)。 此外,只有当这个视图控制器从其shouldAutorotate
方法返回YES时,才会检索支持的方向。 […]系统通过将应用程序的supportedInterfaceOrientationsForWindow:
方法返回的值与最顶级的全屏控制器的supportedInterfaceOrientations
方法返回的值相交来确定是否支持方向。
所以我subclassed UINavigationController
,给了我的MainNavigationController
布尔属性landscapeOK
并用它来返回在supportedInterfaceOrientations
允许的方向。 然后在我的每个视图控制器的viewWillAppear:
方法,我有这样的一行
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
告诉我的MainNavigationController
所需的行为。
问题来了:如果我现在在纵向模式下导航到我的第四个视图,并翻转手机,它会旋转到横向。 现在我按下后退button返回到我的第三个视图,这应该只是工作肖像。 但是它不会回转。 我该如何做到这一点?
我试过了
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]
在我的第三个视图控制器的viewWillAppear
方法,但它什么都不做。 这是错误的方法来调用,或者错误的地方来调用它,或者我应该以完全不同的方式来实现整个事情吗?
我遇到了同样的问题,并find了适合我的解决scheme。 为了使其工作,在你的UINavigationController中实现- (NSUInteger)supportedInterfaceOrientations
是不够的。 你也需要在你的控制器#3中实现这个方法,这是第一个在popup控制器#4之后才是肖像的方法。 所以,我在我的UINavigationController中有以下代码:
- (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { if (self.isLandscapeOK) { // for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown return UIInterfaceOrientationMaskAll; } return UIInterfaceOrientationMaskPortrait; }
在视图控制器#3中添加以下内容:
- (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; }
你不需要添加任何东西到你的视图控制器#1,#2和#4。 这对我有用,我希望它能帮助你。
添加一个CustomNavigationController
重写这些方法:
-(BOOL)shouldAutorotate { return [[self.viewControllers lastObject] shouldAutorotate]; } -(NSUInteger)supportedInterfaceOrientations { return [[self.viewControllers lastObject] supportedInterfaceOrientations]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation]; }
现在在plist中添加所有的方向
在视图控制器中只添加需要的:
-(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; }
这些方法覆盖导航控制器方法
在对所有关于SO的类似问题的每一个答案进行审查后,没有任何答案为我工作,但他们给了我一些想法。 以下是我最终解决问题的方法:
首先,确保项目目标中支持的界面方向包含所需的旋转视图的所有方向。
接下来,做一个UINavigationController
的类别(因为苹果说不要inheritance它):
@implementation UINavigationController (iOS6AutorotationFix) -(BOOL)shouldAutorotate { return [self.topViewController shouldAutorotate]; } @end
将您想要旋转的类别和视图控制器(我将调用RotatingViewController
)导入到最高级别的视图控制器,该视图控制器应该包含您的导航控制器。 在该视图控制器中,执行如下所示的操作。 请注意,这不应该是你想要旋转的视图控制器。
-(BOOL)shouldAutorotate { BOOL shouldRotate = NO; if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) { shouldRotate = [navigationController.topViewController shouldAutorotate]; } return shouldRotate; }
最后,在您的RotatingViewController
,执行shouldAutorotate
和supportedInterfaceOrientations
,如下所示:
-(BOOL)shouldAutorotate { // Preparations to rotate view go here return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate }
你需要这样做的原因是因为iOS 6控制旋转到根视图控制器而不是顶视图控制器。 如果您希望单个视图的旋转与堆栈中其他视图的行为不同,则需要在根视图控制器中为其编写特定的案例。
我没有足够的声望评论@ Brian的答案,所以我会在这里添加我的笔记。
Brian提到iOS6给了rootViewController旋转控制 – 这不仅可以是上面提到的UINavigationController,也可以是UITabBarController,这对我来说也是如此。 我的结构如下所示:
- 的UITabBarController
- UINavigationController的
- UIViewControllers …
- UINavigationController的
- UIViewControllers …
- UINavigationController的
所以我首先在自定义的UITabBarController中添加了方法,然后在自定义的UINavigationController中添加了方法,最后在特定的UIViewController中添加了方法。
来自UITabBarController和UINavigationController的示例:
- (BOOL)shouldAutorotate { return [self.viewControllers.lastObject shouldAutorotate]; } - (NSUInteger)supportedInterfaceOrientations { return [self.viewControllers.lastObject supportedInterfaceOrientations]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return [self.viewControllers.lastObject shouldAutorotateToInterfaceOrientation:toInterfaceOrientation]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation]; }
我想对自己的问题给出部分答案。 我发现下面一行代码,在我的第三个UIViewController
的viewWillAppear
方法中使用:
[[UIDevice currentDevice] performSelector:NSSelectorFromString(@"setOrientation:") withObject:(id)UIInterfaceOrientationPortrait];
但我不太喜欢这个解决scheme。 它使用一个技巧来分配一个只读属性,根据Apple文档,该属性表示设备的物理方向。 这就像告诉iPhone跳到用户手中正确的方向。
我很想把它放在我的应用程序,因为它只是工作。 但是感觉不对,所以我想留下一个干净的解决scheme。
这是我在ios 6.0中用于定向支持
-(BOOL)shouldAutorotate{ return YES; } - (NSUInteger)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskAll; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{ return UIInterfaceOrientationPortrait; }
因为这是一个高度看待的线程。 我想我会添加我认为是最简单的答案。 这适用于ios8及以上
-(BOOL)shouldAutorotate { return YES; }
和
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskPortrait; }
而已。 请享用!
哦,我的ViewControllers被embedded到一个导航控制器中,我不需要任何子类或configuration。
这可能不适用于所有人,但对我来说这很好。 而不是实施…
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
在viewWillAppear在我所有的控制器中,我决定通过重写UINavigationControllerDelegate方法navigationController:willShowViewController:animated:
来集中这个过程在我的UINavigationController子类中navigationController:willShowViewController:animated:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { self.previousVCLandscapeOK = self.isLandscapeOK; // Store the current VC's orientation preference before pushing on the new VC so we can set this again from within the custom "back" method self.isLandscapeOK = NO; // Set NO as default for all VC's if ([viewController isKindOfClass:[YourViewController class]]) { self.isLandscapeOK = YES; } }
我发现这个代理方法不会被调用时,从导航堆栈popup一个VC。 这对我来说不是问题,因为我在我的UINavigationController子类中处理后面的function,这样我就可以为特定的VC设置正确的导航栏button和动作,像这样…
if ([viewController isKindOfClass:[ShareViewController class]]) { UIButton* backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 57, 30)]; [backButton setImage:[UIImage imageNamed:@"back-arrow"] forState:UIControlStateNormal]; [backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; viewController.navigationItem.leftBarButtonItem = backButtonItem; UIImageView* shareTitle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"share-title"]]; [shareTitle setContentMode:UIViewContentModeScaleAspectFit]; [shareTitle setFrame:CGRectMake(0, 0, shareTitle.frame.size.width - 10, shareTitle.frame.size.height - 10)]; viewController.navigationItem.titleView = shareTitle; } else if(...) { ... }
这是我的back
方法看起来像处理从堆栈中popupVC并设置适当的旋转首选项…
- (void)back { self.isLandscapeOK = self.previousVCLandscapeOK; self.previousVCLandscapeOK = NO; [self popViewControllerAnimated:YES]; }
所以,正如你所看到的,基本上所有发生的事情是我第一次设定我的两个属性…
@property (nonatomic) BOOL isLandscapeOK; @property (nonatomic) BOOL previousVCLandscapeOK;
在navigationController:willShowViewController:animated:
这将决定什么样的支持的方向是即将展示的VC内。 当popup一个VC时,我调用了自定义的“后退”方法,然后将isLandscapeOK设置为通过之前的VCLandscapeOK值存储的内容。
正如我所说的,这可能不适用于每个人,但它对我来说很好,我不必担心向我的每个视图控制器添加代码,我可以将它全部集中在UINavigationController子类中。
希望这可以帮助像我这样的人。 谢谢,杰里米。
转到Info.plist文件并进行更改
你想强制iOS 6的应用程序的肖像只有那么你可以添加到UIViewController子类下方的方法
- (BOOL)shouldAutorotate { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { return YES; } else { return NO; } } - (NSUInteger)supportedInterfaceOrientations { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { return UIInterfaceOrientationMaskAll; } else { return UIInterfaceOrientationMaskPortrait; } }
除了一个,我想让所有的VC都locking为纵向。 这是为我工作。
- 在plist文件中添加对所有方向的支持。
-
在根视图控制器中,检测窗口顶部的视图控制器的types,并相应地在supportedInterfaceOrientations方法中设置应用的方向。 例如,我需要我的应用程序只有当webview在堆栈顶部时才能旋转。 以下是我在rootVC中添加的内容:
-(NSUInteger)supportedInterfaceOrientations { UIViewController *topMostViewController = [[Utils getAppDelegate] appNavigationController].topViewController; if ([topMostViewController isKindOfClass:[SVWebViewController class]]) { return UIInterfaceOrientationMaskAllButUpsideDown; } return UIInterfaceOrientationMaskPortrait; }
我没有足够的声望回答@Ram S在@micmdk答复下的问题,所以我会在这里添加我的笔记。
当您使用UITabbarController时 ,请尝试将@ micmdk的代码中的self.viewControllers.lastObject更改为self.selectedViewController,如下所示:
- (BOOL)shouldAutorotate { return [self.selectedViewController shouldAutorotate]; } - (NSUInteger)supportedInterfaceOrientations { return [self.selectedViewController supportedInterfaceOrientations]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [self.selectedViewController preferredInterfaceOrientationForPresentation]; }
我面临同样的问题。 解决了我的问题,如下所示。
如果您使用UINavigationController
来推视图控制器,那么你必须设置下面的方法。
扩展UINavigationController {
override open var shouldAutorotate: Bool { if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))! { return true } return false } override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))! { return .portrait } return .landscapeRight } override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))! { return .portrait } return .landscapeRight }
}
代替LoginViewController
使用你想要显示的UIViewController
。 在我的情况下,我想在Portrait
模式下以Portrait
模式显示其他ViewControllers
中的LoginViewController
。
请使用下面的方法来解决这个问题
- (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; }
只返回你想要的方向!