首页 > 代码库 > 横竖屏任意切换 实战浅析
横竖屏任意切换 实战浅析
前话:前前后后弄了一下午,尝试各种解决方案(估摸有一二十种吧),最后误打误撞终于解决,鉴于在国内国外查找各种解决方法都未能解决,故有此文。(当然stackOverFlow 各种新奇的解决方案,我一一尝试实战,却未能解决,可能是英文还不够好,理解国外解决方案的不够透彻所致,不过稍感欣慰,还是解决了;不管黑猫白猫,能抓耗子就是好猫吧;还真是应了这句话)
需求:整个APP中界面以竖屏为主,且不能自动横竖屏切换,个别播放视频页面可以根据手机的方向横竖屏切换或固定横屏;
苹果系统支持横屏顺序
默认读取plist里面设置的方向(优先级最高)等同于Xcode Geneal设置里面勾选
application window设置的级别次之
然后是UINavigationcontroller
级别最低的是viewcontroller
注:其实这个优先级跟你的window的rootViewcontroller有关系,如果rootViewcontroller是UITabbarViewontroller,那么tabbar就类似前面所说的UINavigationcontroller
翻阅各大网站和论坛我总结了好几种方式,但是大同小异的旋转屏幕的代码,以供参考:
支持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 = UIInterfaceOrientationLandscapeRight;//这里可以改变旋转的方向 [invocation setArgument:&val atIndex:2]; [invocation invoke]; }
或者
//强行旋转,(会导致程序崩溃,而且不会有崩溃日志,很难发现崩溃在哪里,所以使用这个方法的时候一定要注意设置支持的方向) --> 我反正没遇到 我用着好好的
如何手动旋转设备?
Objective-C:
NSNumber *value = http://www.mamicode.com/[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];"orientation"];
不支持ARC版本
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) { [[UIDevice currentDevice] performSelector:@selector(setOrientation:) withObject:(id)UIInterfaceOrientationLandscapeRight]; }
还有一点就是如何判断当前屏幕的方向:可以根据电源的现实方向来判断,苹果提供了这一方法
NSInteger i = [[UIApplication sharedApplication] statusBarOrientation];if (i == UIInterfaceOrientationLandscapeRight){ //在这里可以写相应的代码}
有些人可能想要监听屏幕的自动旋转:
1.注册UIApplicationDidChangeStatusBarOrientationNotification通知(举例:在一个viewcontroller类的viewdidload中注册该通知),示例代码如下: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:)name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];- (void)statusBarOrientationChange:(NSNotification *)notification{ UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; if (orientation == UIInterfaceOrientationLandscapeRight) // home键靠右{ // } if (orientation ==UIInterfaceOrientationLandscapeLeft) // home键靠左 { // } if (orientation == UIInterfaceOrientationPortrait){ // } if (orientation == UIInterfaceOrientationPortraitUpsideDown){ // }}注意这种方式监听的是StatusBar也就是状态栏的方向,所以这个是跟你的布局有关的,你的布局转了,才会接到这个通知,而不是设备旋转的通知。当我们关注的东西和布局相关而不是纯粹设备旋转,我们使用上面的代码作为实现方案比较适合。
2.注册UIDeviceOrientationDidChangeNotification通知(举例:我们同样在一个viewcontroller类的viewdidload中注册该通知),示例代码如下: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientChange:)name:UIDeviceOrientationDidChangeNotification object:nil];- (void)orientChange:(NSNotification *)noti{ NSDictionary* ntfDict = [noti userInfo]; UIDeviceOrientation orient = [UIDevice currentDevice].orientation; /* UIDeviceOrientationUnknown, UIDeviceOrientationPortrait, // Device oriented vertically, home button on the bottom UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left UIDeviceOrientationFaceUp, // Device oriented flat, face up UIDeviceOrientationFaceDown // Device oriented flat, face down */ switch (orient) { case UIDeviceOrientationPortrait: break; case UIDeviceOrientationLandscapeLeft: break; case UIDeviceOrientationPortraitUpsideDown: break; case UIDeviceOrientationLandscapeRight: break; default: break; }}注意到这种方式里面的方向还包括朝上或者朝下,很容易看出这个完全是根据设备自身的物理方向得来的,当我们关注的只是物理朝向时,我们通常需要注册该通知来解决问题(另外还有一个加速计的api,可以实现类似的功能,该api较底层,在上面两个方法能够解决问题的情况下建议不要用,使用不当性能损耗非常大)。
1.在项目中用代码控制视图是否能够自动旋转,支持哪些方向主要是用了下面的三个方法:
- // New Autorotation support.
- //是否自动旋转,返回YES可以自动旋转
- - (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
- //返回支持的方向
- - (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
- // Returns interface orientation masks.
- //这个是返回优先方向
- - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
一般情况下实现前两个方法即可!!这些都是UIViewController的实例方法,直接在需要设置的控制器重写就行...
2.简单介绍我试过的集中方法
1. 这个方法别人说能用,我用了没效果,当时也没看别人的Demo ; 可能有效果吧 ,Demo 见下方
[objc] view plain copy
- //强制旋转屏幕
- - (void)orientationToPortrait:(UIInterfaceOrientation)orientation {
- 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];//前两个参数已被target和selector占用
- [invocation invoke];
- }
调用的时候只需把你想要的方向传过去即可!!
使用的时候有个点需要注意,从A进入B的时候,把B强制转换成横屏,返回的时候,需要在A出现的时候再转换为原来的方向,不然会有问题;个人建议可以在B的viewWillAppear调用这个方法,转换屏幕(例如转换为横屏),然后在A的viewWillAppear中转换回来;
最后附上以上内容的Demo:Demo地址
2.这里有一个用JS 和原生item 控制横竖屏切换的Demo。地址
3.我的方案:
其他界面不支持横屏:
播放界面横屏:
Step1:
在APPDelegate.h文件中增加属性:是否支持横屏
/*** 是否允许横屏的标记 */@property (nonatomic,assign)BOOL allowRotation;
在APPDelegate.m文件中增加方法,控制全部不支持横屏
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { if (self.allowRotation) { return UIInterfaceOrientationMaskAll; } return UIInterfaceOrientationMaskPortrait;}
Step2:
竖屏界面A 跳到 横屏界面B
首先竖屏界面A 配置,直接贴代码了;
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSNumber *value = http://www.mamicode.com/[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
横屏界面B
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
好,关键的两步来了;
1.竖屏界面A 跳到 横屏界面B 一定用presentViewController 跳转 (不知道我说的什么法的,下面的可以不看了)
注:.竖屏界面A---》CFMatchPlayBackViewController 横屏界面B:IJKVideoViewController
IJKVideoViewController *ijk = [[IJKVideoViewController alloc] initWithURL:[NSURL URLWithString:self.replyPath]];
CFMatchPlayBackViewController *VC = ((CFMatchPlayBackViewController *)nextResponder);
__weak __typeof(VC)weakSelf = VC;
ijk.deviceTap = ^ {
NSNumber *value = http://www.mamicode.com/[NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
};
[((UIViewController *)nextResponder) presentViewController:ijk animated:YES completion:nil];
2.横屏界面B 跳转到 竖屏界面A
[self.presentingViewController dismissViewControllerAnimated:NO completion:^{
//
self.deviceTap();
}];
3.重点: 本来这样跳,苹果本身自己是有一个Bug的,就是dismiss掉,回来依然是横屏,而且还是不自适应的横屏;不过解决办法就是 ----> 见下图
4.UIView 横竖屏;最下层加一个View,利用UIView 旋转方法;不失为好方法,亲测也是可用的好办法;看需求吧
后记: 写文章真的是费神费力;但鉴于找遍网上并没有很好的解决方案,故写此文,以帮助像我一样智商一般的孩子;最近赶项目很忙,等空了github 上传Demo; 留言要Demo的,传的会更快哟 !(这是有史以来我写的最清楚的文章,相信聪明的你已经Get到了)
横竖屏任意切换 实战浅析