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

前言

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

常规实现方式的弊端

提到支持横竖屏,大家可能会想到在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 

@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 

@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实现支持某个页面横竖屏切换)