美文网首页iOS
iOS项目中runtime实现支持某个页面横竖屏切换

iOS项目中runtime实现支持某个页面横竖屏切换

作者: mws100 | 来源:发表于2017-03-27 17:55 被阅读323次

    前言

    在项目中,尤其是带视频播放的项目,经常需要视频播放页面横竖屏切换。

    常规实现方式的弊端

    提到支持横竖屏,大家可能会想到在xcode项目配置中,勾选landscape两个选项。在项目中用代码控制页面的横竖屏。这种方案有这么几个缺点:

    • 需要在自定义的tabbarController和navigationController,甚至每个VC中写控制代码
    • plus系列手机横屏模式下,启动app时,简直是杯具(不信的话,你试试有道四六级app)。市面上,有很多有观看课程功能的app都有此类问题。
    • ......

    思考过程

    前段时间,我在项目中也遇到这个问题。由于当时项目紧,没来的及记录。现将实现方案记录下:
    1. 既然以上方案存在几个问题,并且不好解决,那绝不能在xcode中配置横屏。我们知道屏幕横竖切换时,会执行AppDelegate的application:supportedInterfaceOrientationsForWindow:,返回支持的屏幕方向。那应该在这里做操作。
    2.由1又产生了两条思路:

    • 当到需要横屏的vc时,在keywindow最顶层加个特殊命名的view。在此方法中,取出keywindow第一个view。判断。返回横屏还是竖屏。
    • 当需要横屏的vc对象存在时,和销毁时,在此方法做操作。
      我都试了一遍,还是第二种好点。感兴趣的同学可以试试第一种,有问题可以留言讨论。

    3.将2的思路做优化。应该写个工具类,hook此方法,做操作。

    代码实现

    继承自NSObject创建WSLandscapeTool工具类。代码中有注释,不再做说明。

    WSLandscapeTool.h
    
    #import <UIKit/UIKit.h>
    
    @interface WSLandscapeTool : NSObject
    
    /**
     *  在需要横屏的控制器中调用此方法。
        使用前,请先在AppDelegate.m中实现application:supportedInterfaceOrientationsForWindow:方法
     *
     *  @param appDelegate     AppDelegate类 e.g.(AppDelegate *)[UIApplication sharedApplication].delegate
     *  @param needLandscapeVC 需要横屏的控制器
     */
    + (void)allowLandscape:(NSObject *)appDelegate viewController:(UIViewController *)needLandscapeVC;
    
    @end
    
    WSLandscapeTool.m
    
    #import "WSLandscapeTool.h"
    #import <objc/message.h>
    
    @implementation WSLandscapeTool
    
    + (void)allowLandscape:(NSObject *)appDelegate viewController:(UIViewController *)needLandscapeVC {
        //防止循环引用
        __weak typeof(UIViewController *) weakVC = needLandscapeVC;
        
        //方法原始的实现
        IMP originalIMP = method_getImplementation(class_getInstanceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:)));
        
        //被替换后的新实现
        IMP newIMP = imp_implementationWithBlock(^(id obj, UIApplication *application, UIWindow *window){
            if (!weakVC) {
                //VC被释放后,把原来的方法替换回去
                class_replaceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:), originalIMP, method_getTypeEncoding(class_getInstanceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:))));
            }
            return weakVC ? UIInterfaceOrientationMaskAllButUpsideDown : UIInterfaceOrientationMaskPortrait;
        });
        
        //将方法替换
        class_replaceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:), newIMP, method_getTypeEncoding(class_getInstanceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:))));
    }
    
    @end
    

    注意

    方法声明中也写了说明,重复下。使用工具时,需要在AppDelegate.m中实现下supportedInterfaceOrientationsForWindow方法。

    - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
        return UIInterfaceOrientationMaskPortrait;
    }
    

    最后

    个人见解,如有不妥或不明之处,请留言讨论!谢谢!
    这是Demo地址

    相关文章

      网友评论

        本文标题:iOS项目中runtime实现支持某个页面横竖屏切换

        本文链接:https://www.haomeiwen.com/subject/ijbrottx.html