前言
在项目中,尤其是带视频播放的项目,经常需要视频播放页面横竖屏切换。
常规实现方式的弊端
提到支持横竖屏,大家可能会想到在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地址