iOS:禁用子视图的自动旋转
我有支持方向更改的iPad应用程序的嵌套视图层次结构。 它看起来与以下类似。
UIViewController UIView - UIView - UIImageView (disable rotation) - UIImageView - UIView (disable rotation) - UIView - UIView ...
我想locking一些子视图的方向,同时允许其他人自动旋转和resize。 我似乎无法弄清楚如何做到这一点。
一种方法似乎是在willAnimateRotationToInterfaceOrientation:
手动旋转子视图。 鉴于SDK正在执行旋转,我只是将其撤销,这并不是特别有吸引力。
有没有办法简单地禁用方向更改子视图或其他方法来重构我的层次结构?
自动旋转是由视图的UIViewController( shouldAutorotateToInterfaceOrientation:
处理的,因此一种方法是安排层次结构,使得可旋转的视图由一个视图控制器pipe理,而由另一个视图控制器进行不可旋转的视图。 这两个UIViewController的根视图都需要添加到窗口/超级视图。
这里的微妙之处在于,如果在同一级别上有两个视图控制器视图(即通过addSubview:
添加),则只有第一个视图控制器(通常是窗口的rootViewController
)将接收到rootViewController
shouldAutorotateToInterfaceOrientation:
消息。
我自己使用这种方法来实现一个旋转的工具栏,而主视图则没有。
苹果的技术问答QA1688(“为什么我的UIViewController不能随设备一起旋转?”)谈论这个问题。
iOS 6更新:
Autorotation现在使用UIViewController
的shouldAutorotate
和supportedInterfaceOrientations
方法。 shouldAutorotate
默认返回YES
,但是请记住,除了其视图是窗口的直接子视图的rootViewController
之外的视图控制器,无论如何都不会收到旋转callback。
iOS 6示例代码:
使用“单一视图应用程序”模板创build一个新项目,并确保选中“使用情节串联板”。 我们将使用提供的ViewController
类作为旋转视图控制器(如果您喜欢,请重命名它),然后创build第二个名为NonRotatingViewController
UIViewController
子类。 虽然这个视图控制器永远不会收到旋转callback,为了完整和清晰,在NonRotatingViewController.m
添加如下代码:
- (BOOL)shouldAutorotate { return NO; }
在MainStoryboard
文件中,拖出一个新的视图控制器对象,并将其类设置为NonRotatingViewController
,并将其Storyboard ID设置为“NonRotatingVC”。 当你在那里,改变旋转的视图控制器视图的背景颜色清除(不旋转的视图将被添加到这个下面),并添加一个标签到每个视图。 在AppDelegate.m
,添加以下代码:
#import "NonRotatingViewController.h" // ... // ... - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil]; NonRotatingViewController *nonRotatingVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"NonRotatingVC"]; [self.window addSubview:nonRotatingVC.view]; return YES; }
这只是实例化一个不旋转的视图控制器,并直接将其视图添加到窗口(注意这个窗口的rootViewController
已经由故事板设置)。
运行该项目。 旋转设备,惊叹于一个旋转的标签,而另一个停留!
示例代码pre iOS 6:
我在一个新的项目中做了这个 – 一个新的基于视图的应用程序将会很好。 添加两个新的视图控制器: RotatingViewController
和NonRotatingViewController
。 在每个笔尖里面,我只是添加了一个标签来描述视图是否旋转。 添加下面的代码:
' RotatingViewController.m
'
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; }
' NonRotatingViewController.m
'
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if (interfaceOrientation == UIInterfaceOrientationPortrait) { // Or whatever orientation it will be presented in. return YES; } return NO; }
' AppDelegate.m
'
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RotatingViewController *rotating = [[RotatingViewController alloc] initWithNibName:@"RotatingViewController" bundle:nil]; self.rotatingViewController = rotating; [rotating release]; NonRotatingViewController *nonRotating = [[NonRotatingViewController alloc] initWithNibName:@"NonRotatingViewController" bundle:nil]; self.nonRotatingViewController = nonRotating; [nonRotating release]; [self.window addSubview:self.rotatingViewController.view]; [self.window insertSubview:self.nonRotatingViewController.view belowSubview:self.rotatingViewController.view]; [self.window makeKeyAndVisible]; return YES; }
我希望这有帮助。
这是另一种方式。 只要把这段代码放到你的viewController的viewDidLoad中:
YourAppDelegate *delegate = [[UIApplication sharedApplication] delegate]; // the view you don't want rotated (there could be a heierarchy of views here): UIView *nonRotatingView = [[UIView alloc] initWithFrame:CGRectMake(100,0,30,500)]; nonRotatingView.backgroundColor = [UIColor purpleColor]; // make sure self.view and its children are transparent so you can see through to this view that will not be rotated behind self.view. [delegate.window insertSubview:nonRotatingView belowSubview:self.view]; // you can't put it in the front using: // [delegate.window insertSubview:nonRotatingView aboveSubview:self.view]; // It will show up the same as before // you should declare nonRotatingView as a property so you can easily access it for removal, etc.
我解决这个问题的方法是采取一个对策,使用UINotification
来检测自动旋转和UINotification
旋转视图。
在这里find完整的代码:
https://gist.github.com/ffraenz/5945301
- (void)orientationDidChangeNotificationReceived:(NSNotification *)notification { // find out needed compass rotation // (as a countermeasure to auto rotation) float rotation = 0.0; if (self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) rotation = M_PI; else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) rotation = M_PI / 2.0; else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) rotation = M_PI / (- 2.0); // rotate compass without auto rotation animation // iOS rotation animation duration is 0.3 // this excludes the compassView from the auto rotation // (same effect as in the camera app where controls do rotate and camera viewport don't) [UIView animateWithDuration:0.3 animations:^(void) { self.compassView.transform = CGAffineTransformMakeRotation(rotation); }]; }