横竖屏任意切换 实战浅析

前话:前前后后弄了一下午,尝试各种解决方案(估摸有一二十种吧),最后误打误撞终于解决,鉴于在国内国外查找各种解决方法都未能解决,故有此文。(当然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 = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:@"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.在项目中用代码控制视图是否能够自动旋转,支持哪些方向主要是用了下面的三个方法:

[objc] view plain copy

  1. // New Autorotation support.
  2. //是否自动旋转,返回YES可以自动旋转
  3. - (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
  4. //返回支持的方向
  5. - (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
  6. // Returns interface orientation masks.
  7. //这个是返回优先方向
  8. - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

一般情况下实现前两个方法即可!!这些都是UIViewController的实例方法,直接在需要设置的控制器重写就行...

2.简单介绍我试过的集中方法

1.  这个方法别人说能用,我用了没效果,当时也没看别人的Demo  ; 可能有效果吧  ,Demo 见下方


[objc]
 view plain copy

  1. //强制旋转屏幕
  2. - (void)orientationToPortrait:(UIInterfaceOrientation)orientation {
  3. SEL selector = NSSelectorFromString(@"setOrientation:");
  4. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
  5. [invocation setSelector:selector];
  6. [invocation setTarget:[UIDevice currentDevice]];
  7. int val = orientation;
  8. [invocation setArgument:&val atIndex:2];//前两个参数已被target和selector占用
  9. [invocation invoke];
  10. }

调用的时候只需把你想要的方向传过去即可!!

使用的时候有个点需要注意,从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 = [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 = [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到了)

时间: 2024-12-21 17:31:57

横竖屏任意切换 实战浅析的相关文章

修正Android基于ZXing的二维码扫描——横竖屏自由切换

概述: 此博客是基于开源的框架ZXing.ZXing用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口.ZXing可以实现使用手机的内置的摄像头完成条形码的扫描及解码.该项目可实现的条形码编码和解码. 资源下载: http://download.csdn.net/detail/u013761665/8853561 修改为竖屏显示: 第1步: 进入com.google.zxing.client.android包下的CaptureActivity类: 注释以下代码: i

IOS强制屏幕横竖屏相互切换

最近项目要做一个html5电子协议,里面涉及到签名,竖屏签名不够,所以需要把屏幕切换到横屏,签完字后把签字内容返回到竖屏中的方框内,由于项目不上AppStore,只用企业证书打包,所以使用下面方式来实现横竖屏切换功能. bool isPortrait = true; - (IBAction)changeOri:(id)sender { if (isPortrait) { if ([[UIDevice currentDevice] respondsToSelector:@selector(setO

Android(十八)横竖屏的切换

1.强制横竖屏. 这就需要通过在AndroidManifest.xml中设置activity中的android:screenOrientation属性值来实现. 该android:screenOrientation属性,他有以下几个参数: "unspecified":默认值 由系统来判断显示方向.判定的策略是和设备相关的,所以不同的设备会有不同的显示方向. "landscape":横屏显示(宽比高要长) "portrait":竖屏显示(高比宽要长

强制横竖屏间切换

if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) { SEL selector = NSSelectorFromString(@"setOrientation:"); if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation])) { NSInvocation *invocation = [NS

浅析Android的横竖屏切换

上周有个项目需求在横竖屏中控制不一样的布局,我当时采用的方法是写在同一套布局中,监听手机横竖屏的切换事件,来控制布局中各个控件的显示或者隐藏. 这个方法相对来说还行.上几篇帖子中我也说了怎么判断当前手机是横屏模式还是竖屏模式,这里再把工具类贴一下给大家看看: public static boolean isScreenChange(Context mContext) { Configuration mConfiguration = mContext.getResources().getConfi

Android应用:横竖屏切换总结

眨眼间,已经到了2016你年春节前,离上一篇博客的时间已经有6个月多,回想起这半年的种种,不得不说,学习和工作实在是太忙了,或许这就是程序员的真实写照吧. 写博客之初,主要的目的还是为了把自己的学习痕迹记录下来,写的东西比较基础,也不多,算是一种督促,希望能坚持地学习下去,因为学识不存在暴发户,靠的是积累.如果对自己过去半年的学习给个评价,我还是比较满意的,前期定下来的目标都基本都达到了.单凭这个,我就觉得今年的新年会是个好年. 说完过去,那么接着就是将来.因为现在的工作环境上外网不大方便,而且

Android横竖屏切换及其对应布局加载问题

第一,横竖屏切换连带横竖屏布局问题: 如果要让软件在横竖屏之间切换,由于横竖屏的高宽会发生转换,有可能会要求不同的布局. 可以通过以下两种方法来切换布局: 1)在res目录下建立layout-land和layout-port目录,相应的layout文件名不变,比如:layout-land是横屏的layout,layout-port是竖屏的layout,其他的不用管,横竖屏切换时程序调用Activity的onCreate方法中的setOnContent(xxx),并自动加载相应的布局. 2)假如布

Android横竖屏切换重载问题与小结

(转自:http://www.cnblogs.com/franksunny/p/3714442.html) (老样子,图片啥的详细文档,可以下载后观看 http://files.cnblogs.com/franksunny/635350788930000000.pdf) Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是有时候也不尽然,通常在设置里面我们可以对手机的横竖屏切换进行关闭,操作界面如下 只需要点击下“屏幕旋转”按钮就可以关闭横竖屏切换了. 一.禁止AP

横竖屏切换

很多时候会用到屏幕旋转时需要对一些数据进行保存,例如当横竖屏区切换时要保存先前屏幕的一些数据和状态,个人认为有两个方法提供使用: 1.当前的Activity不销毁: 那么就需要在AndroidManifest.xml配置文件中的Activity标签下面添加:android:configChanges="orientation|keyboardHidden" 然后在activity中重写onConfigurationChanged()方法,每次旋转时会调用该方法,可以再该方法中处理数据