参考:http://blog.sina.com.cn/s/blog_6291e42d0102v0th.html
1.工程配置和回调方法
在工程的配置选项里, 可以设置程序所允许的方向;
在配置选项的前提下, 在视图控制器里有关于当前视图可允许的旋转回调, 这个回调只对rootViewController和presentedViewController有效, 对于子级的视图控制器无效. 例如UINavigationController作为根视图时, 旋转回调需要设置在UINavigationController上, 设置在UINavigationController的子控制器上是没有效果的.
2.关于方向
这里有三种方向:手机方向[[UIDevice currentDevice] orientation], 程序方向[[UIApplication sharedApplication] statusBarOrientation], 视图方向.
手机方向: set方法被官方作为私有api禁用, 但是可以绕过限制. 这个方法可以看做是摇动手机. 据我估计, 旋转手机时, 系统会调用这个set方法, 所以, 当想要不旋转手机而使屏幕旋转时, 需要主动调用这个方法. 实际旋转效果会受到工程配置项和回调方法的影响.
程序方向: 实际旋转效果会受到工程配置项和回调方法的影响.
视图方向: 通过设置transform属性可以使视图旋转, 但是如果此时有键盘或者提示框或者状态栏存在, 会发现它们仍是原来的方向.
3.旋转方案
方案1:调用[[UIDevice currentDevice] setOrientation:]方法, 使程序旋转, 需要配置旋转回调, 回调的配置必须在根视图上
@implementation ViewController
- (void)loadView
{
[super loadView];
UIButton *showButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
showButton.frame = CGRectMake(210, 20, 50, 50);
showButton.layer.borderWidth = 1;
[showButton setTitle:@"旋转" forState:UIControlStateNormal];
[showButton addTarget:self action:@selector(showButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:showButton];
}
- (void)showButtonPressed
{
if (self.bLandscapeRight)
{
self.bLandscapeRight = NO;
[self forceOrientation:UIInterfaceOrientationPortrait];
}
else
{
self.bLandscapeRight = YES;
[self forceOrientation:UIInterfaceOrientationLandscapeRight];
}
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return self.bLandscapeRight ? UIInterfaceOrientationMaskLandscapeRight : UIInterfaceOrientationMaskPortrait;
}
- (void)forceOrientation: (UIInterfaceOrientation)orientation
{
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
{
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget: [UIDevice currentDevice]];
int val = orientation;
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
@end
方案2:弹出新的presentedViewController, 并设置其方向
UILandscapeView *landscapeView = [[UILandscapeView alloc] init];
[self presentViewController:landscapeView animated:YES completion:nil];
@implementation UILandscapeView
- (void)loadView
{
[super loadView];
self.view.backgroundColor = [UIColor orangeColor];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(20, 20, 180, 50)];
textField.backgroundColor = [UIColor redColor];
textField.text = @"1111122222";
[self.view addSubview:textField];
UIButton *showButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
showButton.frame = CGRectMake(210, 20, 50, 50);
showButton.layer.borderWidth = 1;
[showButton setTitle:@"弹框" forState:UIControlStateNormal];
[showButton addTarget:self action:@selector(showButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:showButton];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
backButton.frame = CGRectMake(270, 20, 50, 50);
backButton.layer.borderWidth = 1;
[backButton setTitle:@"返回" forState:UIControlStateNormal];
[backButton addTarget:self action:@selector(backButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (void)backButtonPressed
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)showButtonPressed
{
}
@end
以下是过去的想法
1. 利用通常的方式来控制旋转方向: 在工程配置中允许设备向某几个方向旋转, 然后在某个视图只允许向某几个方向旋转;
2. 利用消息中心 [NSNotificationCenter defaultCenter] 来监测设备旋转, 哪怕在工程配置中不允许的旋转方向, 也会被监测到, 并且检测到的方向是UIDeviceOrientation代表的七种方向;
3. 利用私有API或者是隐藏的API接口, 主动使界面旋转, 哪怕设备并没有转动;
4. 利用view.transform属性来旋转视图, 缺点是: 当有系统控件, 比如UIAlertView时, 这个控件的方向还是原来的;
一般方法
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft; // 允许旋转的方向
}
- (BOOL)shouldAutorotate
{
return YES;
}
消息中心
- (void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceRotated:) name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];
}
- (void)deviceRotated:(UIButton*)button
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
}
强制旋转
- (void)manulRotate:(UIButton*)button
{
UIDeviceOrientation oldOrientation = [[UIDevice currentDevice] orientation];
UIDeviceOrientation newOrientation = (oldOrientation == UIDeviceOrientationLandscapeRight) ? UIDeviceOrientationPortrait : UIDeviceOrientationLandscapeRight;
NSLog(@"orientation from old(%d) to new(%d)", oldOrientation, newOrientation);
// 调用私有API(禁用ARC时)
//if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
// [[UIDevice currentDevice] performSelector:@selector(setOrientation:) withObject:(id)UIInterfaceOrientationLandscapeRight];
// 调用私有API(启用ARC时)
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
{
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = newOrientation;
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
旋转视图
- (void)viewRotate:(UIButton*)button
{
// 旋转window
//self.view.window.transform = CGAffineTransformRotate(self.view.window.transform, M_PI/2);
// 旋转view
self.view.transform = CGAffineTransformRotate(self.view.transform, M_PI/2);
}