这是我的代码。
SomeController *analyticsViewController = [[SomeController alloc] init];
MTNavigaionLandscapeViewController *analyticsNavigaionObject = [[MTNavigaionLandscapeViewController alloc] initWithRootViewController:analyticsViewController];
[analyticsNavigaionObject setNavigationBarHidden:YES];
if ([self respondsToSelector:@selector(presentModalViewController:animated:completion:)]) {
[self presentViewController:analyticsNavigaionObject animated:YES completion:nil];
} else {
[self presentModalViewController:analyticsNavigaionObject animated:YES];
}
[analyticsViewController release];
[analyticsNavigaionObject release];
以下是SomeController.m中支持的方向
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
支持MTNavigaionLandscapeViewController(UINavigationController的子类)的方向
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
最后,如果我只提供SomeController,它工作正常..我的问题是当我提出Navigationcontroller然后问题发生。请帮帮我
答案 0 :(得分:2)
如何强制iPhone旋转到某个方向。
问题
iPhone和iPad应用可支持纵向或横向或两者兼备。有时,单个或极少数视图需要仅以纵向或横向显示,或者以其他应用程序不支持的方向显示。 iOS或cocoa框架分别提供了为每个视图单独定义的方法,支持哪些方向。但是,除非任何限制适用于所有应用程序并因此分别在项目或目标级别定义,否则始终是用户必须执行轮换。应用程序可以决定它是否支持某个方向,但它不能强制系统实际旋转。
本教程展示了如何克服这种不足。
给出的示例是针对iPhone应用程序,它以纵向模式呈现除了一个视图控制器之外的所有视图控制器。出于良好的设计和可用性原因,其中一个视图控制器仅在横向上工作。
到目前为止,这已在iPhone iOS 6上得到证实。
旋转模态显示的视图控制器
当视图以模态方式呈现时,此任务很容易。 对于模态呈现的视图控制器,呈现的视图控制器应仅支持横向,并且在呈现视图模式之前,视图控制器的方向应设置为横向。
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:YES];
[self presentModalViewController:landscapeVC animated:YES];
这样,视图控制器landscapeVC
将以横向显示。
但要保留导航栏等,我想将其推送到导航控制器的堆栈。不幸的是,除非用户实际旋转它,否则设备不会旋转其方向。
此外,我的应用程序有两个目标。其中一个的导航基于标签栏,另一个目标的导航(功能减少免费版本)很简单。因此,我的解决方案需要同时包含标签栏和应用程序的应用程序。
因此,对于仅具有标签栏或根本没有标签栏的应用程序,此解决方案可能过大。但它无论如何都适用。
标签栏控制器的方向问题
当标签栏显示其视图控制器时,它是控制方向的标签栏控制器。实际上,这意味着内部呈现的所有视图都应该支持所有相同的方向。
为了解决这个问题,我们需要继承UITabBar
并引入一些控制标签栏是否应该支持横向的功能。
对应用程序委托的更改
在我的例子中,我向应用程序委托添加了一个布尔变量。这是因为使用标签栏或没有标签栏运行的双重性。如果只有标签栏,则可以将该变量作为属性添加到标签栏子类中。对于本书中的OOP,单例会很好但我认为对于单个布尔开关来说有点过大。
AppDelegate.h:
@property BOOL isLandscapePreferred;
它是自动合成的。默认值为NO
。不过,您可能希望在应用代理中NO
明确设置application:didFinishLoadingWithOptions:
。
对于没有标签栏的目标,我的所有视图控制器都需要响应该设置。基本上,呈现景观视图的人必须实现以下内容。但是,如果您的应用程序中有多个视图需要在横向中显示,那么在整个应用程序中使用它并不会有害。
对UIApplication的更改
根据我在网上找到的一些建议,我决定将UIApplication子类化并覆盖supportedInterfaceOrientations
。但是,我仍然在xcode中的目标的“摘要”窗格中标记了所有方向,尽管该设置应该被UIApplication覆盖。
MyApp.h和MyApp.m:
#import <UIKit/UIKit.h>
@interface MyApp : UIApplication
@end
#import "MyApp.h"
#import "AppDelegate.h"
@implementation MyApp
- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if ([(AppDelegate*) [[UIApplication sharedApplication] delegate] isLandscapePreferred]) {
return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeLeft);
NSLog(@"PhotocollApp: Landscape");
} else {
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
NSLog(@"PhotocollApp: Portrait");
}
}
@end
从主
调用MyApp接下来,我们需要确保在应用程序启动时实现我们的子类应用程序对象。这需要改变main.m.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "PhotocollApp.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, NSStringFromClass([MyApp class]), NSStringFromClass([AppDelegate class]));
}
}
UIApplicationMain
在前两个参数中传递了两个接收的参数argc
和argv
,后跟两个NSString
个对象,表示应用程序类的名称和一个应用程序代表班。我没有更改应用程序委托的标准名称,但我们需要在此处标识自己的应用程序类。
覆盖所有视图控制器中的supportedInterfaceOrientations
我介绍了UIViewController
和UITableViewController
的“抽象”子类。我的所有视图控制器都继承自它们:
MyRotatingViewController.h和.m:
#import <UIKit/UIKit.h>
@interface MyRotatingViewController : UIViewController
@end
#import "MyRotatingViewController.h"
#import "AppDelegate.h"
@implementation MyRotatingViewController
// …
#pragma mark - Rotation Management
- (BOOL) shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([(AppDelegate*) [[UIApplication sharedApplication] delegate] isLandscapePreferred]) {
return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeLeft);
} else {
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
}
}
@end
MyRotatingTableViewController
完全相同。唯一的区别在于.h文件。当然,它继承自UITableViewController
。
#import <UIKit/UIKit.h>
@interface MyRotatingTableViewController : UIViewTableController
@end
确保所有(受影响的)视图控制器分别从MyRotatingViewController
或MyRotatingTableViewController
继承。而不是实现这个&#34;摘要&#34;您当然可以在所有相关视图控制器中实现shouldAutorotate
和supportedInterfaceOrientations
。
自定义标签栏类
如上所述,在标签栏驱动的应用程序中,标签栏的方法控制方向设置,而不是标签栏显示的视图控制器。
// MyTabBarController.h
#import <UIKit/UIKit.h>
@interface MyTabBarController : UITabBarController
@end
// MyTabBarController.m
#import "MyTabBarController.h"
#import "AppDelegate.h"
@interface MyTabBarController ()
@end
@implementation MyTabBarController
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Rotation Management
- (BOOL) shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([(AppDelegate*) [[UIApplication sharedApplication] delegate] isLandscapePreferred]) {
return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeLeft);
} else {
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
}
}
@end
当我使用故事板时,我只需要在IB中唯一的标签栏对象的属性窗格中设置MyTabBarController
。如果您以编程方式创建它,则只需实例化MyTabBarController
而不是UITabBarController
。
调用视图控制器强制显示
根据80/20规则,我们只有80%准备20%的实际工作。 现在真正的工作来了......
这是视图控制器的非常方法的中间,其中推送了横向视图。在我的情况下,这是在tableView:didSelectRowAtIndexPath:
实现中。它当然可以在IBAction
方法或prepareForSegue:sender:
方法内。如果在prepareForSegue
中执行此操作,则在运行时可能会在错误控制台上出现警告。我一方面没有看到任何故障,但另一方面,当应用程序提交到商店时,我不知道这是否会通过或导致拒绝。
诀窍是将状态栏的方向设置为横向,然后以模态方式显示视图控制器。现在设备处于横向模式。到目前为止,用户不应该看到任何东西。即使裸视图控制器没有视图。根本不会显示零视图。 接下来,最近呈现的视图控制器被解雇。 之后,真实视图控制器将被推送到导航堆栈。
这是代码:
//set the landscape switch for the tab bar, view controllers and application
[(AppDelegate*) [[UIApplication sharedApplication] delegate] setIsLandscapePreferred:YES];
//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:YES];
// Create any view controller. UIViewController will do.
// Present it modally and directly after that dismiss it again.
UIViewController *anyVC = [[UIViewController alloc] init];
[self presentModalViewController: anyVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
// The user should not have noticed anything but how the device is in landscape orientation
//Frankly I am not sure whether the next statement must be included or does not need to be.
//While working on “my” solution I came across a number of tricks and hints on several places on the web and this was amongst them.
//At least it does not do any harm.
if ([UIViewController respondsToSelector:@selector(attemptRotationToDeviceOrientation)]) {
// this ensures that the view will be presented in the orientation of the device
// This method is only supported on iOS 5.0. iOS 4.3 users may get a little dizzy.
[UIViewController attemptRotationToDeviceOrientation];
}
// Get the storyboard named secondStoryBoard from the main bundle:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
// I am using storyboard in this project. If you don’t do that then you could just instantiate the view controller the usual way with alloc/init or by loading from nib.
LandscapeVC *landscapeVC = (landscapeVC *)[storyBoard instantiateViewControllerWithIdentifier:@"LandscapeVC"];
// Then push the new view controller in the usual way:
[self.navigationController pushViewController:paintingVC animated:YES];
横向视图控制器
我们快到了。现在,新的视图控制器LandscapeVC
以横向模式显示在标签栏应用上。对于没有标签栏的应用,我们必须对LandscapeVC
视图控制器本身应用一些更改。当然,我们需要确保在横向模式下取消视图控制器时将设备旋转回纵向。
LandscapeVC.m的小册子
#pragma mark - actions
// certain tasks need to be performed before the view controller is dismissed. This could be done within the viewWillDisappar.
// Again, if you do that in viewWillDisappear: then you risk some warnings on the console. I have decided to overlay the “Back” button (leftBarButtonItem) with a custom button that invokes the following action.
- (IBAction)done :(id)sender{
//set the landscape switch back to off/NO/portrait
[(AppDelegate*) [[UIApplication sharedApplication] delegate] setIsLandscapePreferred:NO];
//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[UIViewController alloc] init];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
[self.navigationController popViewControllerAnimated:YES];
return;
}
#pragma mark - Rotation
// Rotation
-(BOOL)hidesBottomBarWhenPushed{
// This one is just for my design. I like to use the full screen of the iPhone for my landscape view controller.
// In the end it is the size of the pane in my case which motivates me to break with UI guidelines and force the user to use this single view controller in landscape only.
// Besides this design issue this method is not required for the rotation itself.
// What it does: It overwrites the getter of the UIViewController property hidesBottomBarWhenPushed.
// By returning YES as constant the bottom bar (= tab bar in my case) will be hidden.
// However, it remains hidden in the event that any more view controllers are pushed on top of the navigation stack.
// So if you plan to drill further down in your navigation from here, it may not be a good idea to hide the bottom bar.
// You will not get it back until the user returns to the calling view controller.
return YES;
}
// Well, if all of your view controllers inherit from MyRotatingViewController or MyRotatingTableViewController
// respectively then the following is redundant.
// While writing this “tutorial” for stack overflow I noticed that this
// very view controller does not. Don’t ask me why. I may fix it later.
// However, I want to show to you what is proven to work fine. Therefore I owe you these methods.
-(BOOL)shouldAutorotate{
return NO;
}
- (NSInteger)supportedInterfaceOrientations{
return (UIInterfaceOrientationLandscapeRight | UIInterfaceOrientationLandscapeLeft);
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return (UIInterfaceOrientationLandscapeLeft);
}
就是这样。挺直的,不是吗?
答案 1 :(得分:1)
在您将要呈现的ViewController中编写这些方法:
- (BOOL)shouldAutorotate
{
AppDelegate *mainDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
mainDelegate.shouldRotate = YES;
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
在AppDelegate.m中粘贴
- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.shouldRotate)
{
self.shouldRotate = NO;
return UIInterfaceOrientationMaskLandscapeRight;
}
return UIInterfaceOrientationMaskPortrait;
}
在AppDelegate.h中粘贴
@property (assign, nonatomic) BOOL shouldRotate;
在ViewWillAppear中的presentsViewController中粘贴:
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];