iOS强制横屏总结

http://www.jianshu.com/p/5c773628caa6

总体方向两点:
model下,present方式推出界面。
push横屏,带tabbar、navigation,且一个item下所有控制器对应的只有一个根navigation。
接下来说说push方式强制旋转横屏时遇到的坑吧.....

遇到的问题描述:
横着,竖屏切换到横屏,是否“锁定竖屏”,都会偶尔造成无法旋转至横屏,iOS8表现较明显。
横着或竖着,切换到横屏,挂起,再进入横屏,退出,再进入横屏,反复切换,偶尔会导致无法横屏,返回上竖屏时,界面返回了,但横屏无法返回。
横竖屏来回切换,跳转,iOS8下,横屏控制器,竖屏控制器中init方法,横屏中viewWillDisapper、viewWillApper,调用顺序会乱,与iOS7、9执行的顺序不一样,个人感觉应该是push强制横屏或都是同一个navigation导致的原因吧。
 

小总结下:
由于该项目横屏中有来回跳转,到处跳转的,一个item下对应的根控制下又只能是同一个navigation,分享模块又是基于tabbar上的navigation推出的,分享模块无回调,导致我瞻前顾后的,一直盯着push方式到底是否可以强制旋转屏幕........百般绞尽脑汁的研究

思来想去的,就参考了爱奇艺横屏播放视频的方式,横屏中的跳转都先回到竖屏播放控制器中跳转,相当于横屏中跳转多了一层过渡控制器;竖屏返回,应该是返回根控制器,所以,横屏应该是一个新的navigation,而分享都是在横屏中处理的。而我这项目中,分享的列表是在tabbar上的navigation加在windows上的,分享跳转都是基于tabbar的navigation,故无法再新建navigation,否则会引发一系列问题,比如无法跳转至首页,基本上各种在横屏里面的老代码跳转方式都不行了。

故此,我又回到全部push方式继续坑........

因为我也不想啊,如果用present方式涉及改动的代码模块太多了.....

其实有点不明白的是,产品为何如此设计:横屏和竖屏,全模块之间的跳转,试问这样真的好吗.........

接下来分析下push方式,仅限于参考和积累问题吧:

解决方案:
先说下思路吧:

1、实时的更新当前应用所支持的方向,手动调用方法-    (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window;
2、把当前控制器的方向给到当前navigation,一定要保证统一,不能乱套,否则会导致界面来回跳转错乱的问题;
3、及时刷新当前控制器,手动调用方法[UIViewController attemptRotationToDeviceOrientation]。

一、 present方式:
就不多说了,调用系统的三个方法,基本上没什么问题。

二、push方式:
基类tabbar代码:

#pragma mark - - orientation
// 是否支持转屏
- (BOOL)shouldAutorotate
{
    return [self.selectedViewController shouldAutorotate];
}
// 返回nav栈中的最后一个对象支持的旋转方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return [self.selectedViewController supportedInterfaceOrientations];
}
// 返回nav栈中最后一个对象,坚持旋转的方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}

基类navigation代码:

// 旋转方向 默认竖屏
@property (nonatomic , assign) UIInterfaceOrientation interfaceOrientation;
@property (nonatomic , assign) UIInterfaceOrientationMask interfaceOrientationMask;

#pragma mark - - orientation
// 设置是否允许自动旋转
- (BOOL)shouldAutorotate 
{
    return YES;
}

// 设置支持的屏幕旋转方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations 
{
  return self.interfaceOrientationMask;
}

// 设置presentation方式展示的屏幕方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation 
{
  return self.interfaceOrientation;
}

 

基类BaseViewController代码:

- (void)viewDidLoad
{
  [super viewDidLoad];
  [UIViewController attemptRotationToDeviceOrientation];
}

 

AppDelegate代码

@property (assign , nonatomic) BOOL isForceLandscape;
@property (assign , nonatomic) BOOL isForcePortrait;

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
  if (self.isForceLandscape) 
  {
      return UIInterfaceOrientationMaskLandscape;
  }
  else if (self.isForcePortrait)
  {
      return UIInterfaceOrientationMaskPortrait;
  }
  return UIInterfaceOrientationMaskPortrait;
}


横屏viewController代码:
重点说明:
1、此处需要手动调用

 

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window;

且设置当前 应用只支持横屏;
因为,该方法在viewWillAppear之后执行的。
2、更新了支持的方向后,记得刷新下控制器,调用:

[UIViewController attemptRotationToDeviceOrientation];

否则,[UIScreen mainScreen].bounds的size不是你期望的;self.view.frame/bounds都不是期望的。
3、其实网上说的一些普通的方式实现横屏,问题多,更多的是因为" self.view.frame/bounds/[UIScreen mainScreen].bounds "没有及时更新的。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    //强制旋转竖屏
    [self forceOrientationLandscape];
    CKNavigationController *navi = (CKNavigationController *)self.navigationController;
    [self.navigationController setNavigationBarHidden:YES animated:animated];
    navi.interfaceOrientation =   UIInterfaceOrientationLandscapeRight;
    navi.interfaceOrientationMask = UIInterfaceOrientationMaskLandscapeRight;

    //强制翻转屏幕,Home键在右边。
    [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeRight) forKey:@"orientation"];
    //刷新
    [UIViewController attemptRotationToDeviceOrientation];
}


重点说明:
1、离开横屏时、横屏中跳转,记得强制旋转至竖屏;
2、如果没有及时旋转至横屏,会导致" [UIScreen mainScreen].bounds "没有及时更新,从而影响其它模块的布局问题;

 

- (void)viewWillDisappear:(BOOL)animated 
{
    [super viewWillDisappear:animated];
     //强制旋转竖屏
    [self forceOrientationPortrait];
    CKNavigationController *navi = (CKNavigationController *)self.navigationController;
    navi.interfaceOrientation = UIInterfaceOrientationPortrait;
    navi.interfaceOrientationMask = UIInterfaceOrientationMaskPortrait;


     //设置屏幕的转向为竖屏
    [[UIDevice currentDevice] setValue:@(UIDeviceOrientationPortrait) forKey:@"orientation"];
    //刷新
    [UIViewController attemptRotationToDeviceOrientation];
}
#pragma  mark 横屏设置
// 强制横屏
- (void)forceOrientationLandscape
{
    CKAppDelegate *appdelegate=(CKAppDelegate *)[UIApplication sharedApplication].delegate;
    appdelegate.isForceLandscape=YES;
    appdelegate.isForcePortrait=NO;
    [appdelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
}

// 强制竖屏
- (void)forceOrientationPortrait
{
    CKAppDelegate *appdelegate=(CKAppDelegate *)[UIApplication sharedApplication].delegate;
    appdelegate.isForcePortrait=YES;
    appdelegate.isForceLandscape=NO;
    [appdelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
}

- (BOOL)prefersStatusBarHidden
{
    return YES;
}


感受,网上找了很多种方法,关于这个方法有人说上架可能会被拒,虽然是间接调用私有方法。
但这个方法经过多轮测试,其实不是有用的,不靠谱,只要按照我上面说的步骤测试,绝对会有bug的,故此不建议大家使用该方法。

 

 

- (void)interfaceOrientation:(UIInterfaceOrientation)orientation
{
  if ([[UIDevicecurrentDevice] respondsToSelector:@selector(setOrientation:)])
  {        
      SEL selector  =NSSelectorFromString(@"setOrientation:");
      NSInvocation*invocation = [NSInvocationinvocationWithMethodSignature [UIDeviceinstanceMethodSignatureForSelector:selector]];     
      [invocation setSelector:selector];        
      [invocation setTarget:[UIDevicecurrentDevice]];
      intval = orientation;
      // 从2开始是因为0 1 两个参数已经被selector和target占用
      [invocation setArgument:&val atIndex:2];                                                     
      [invocation invoke];   
  }
}

 

以上所述,支持iOS7、8、9系统,经iphone \iPod测试过,但貌似iOS8从横屏挑战至其它竖屏的界面,偶尔会有问题,概率很小,不影响。
原因:可能是iOS8 SDK与其它不同吧。

更新iOS8的问题:
 iOS8-8.4,横屏跳转至其它界面,最好延迟跳转,不然其它界面的viewWillApper会比横屏的viewWillDisApper先执行,导致无法旋转回来。

CGFloat timef = 0.8;
// 主要是转屏之后view的再次旋转
if (kSystemVersion>8||kSystemVersion<8.4) 
{
        self.view.hidden = YES;
        [self viewWillDisappear:NO];
        timef = 0.1;
}
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, timef*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
        dispatch_async(dispatch_get_main_queue(), ^(){
           // 跳转界面
        });
});

 

 

 

 

 

参考资料:
http://www.cocoachina.com/bbs/read.php?tid=244119

 

 

 

你可能感兴趣的:(iOS,开发编码收集)