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 <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地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 关于横竖屏适配,有一句说一句,坑挺深的。之前做Vision和毕设的时候就处理过横竖屏问题,不过当时的功力太浅,明显...
    HarwordLiu阅读 37,449评论 26 137
  • 由于项目需求,需要实现app中的其中一个页面支持横竖屏,由于之前接触此方面甚少,着实花费了一些时间研究~怕自己忘记...
    桃子王阅读 1,757评论 2 1
  • 概述 写代码就是在不断填坑的过程中慢慢成长,程序员哪有不遇坑的呢? 这篇文章来谈谈iOS中横竖屏切换的一些坑,横竖...
    jumpingfrog0阅读 11,394评论 6 21
  • 【跑步不是一种任务,它是一种当代非常少时间能够进行自我交流的一种形式,这种超越形式交流的沟通,在当代的快节奏的生活...
    贺小桶阅读 204评论 0 1
  • 世界上有一個“一”,就會有一的對立面, 任何事物都有他的對立面了吧, 熱 和 冷, 善 和 惡 , 高興 和 悲傷...
    蘇步阅读 289评论 0 1