前言
在項(xiàng)目中,尤其是帶視頻播放的項(xiàng)目,經(jīng)常需要視頻播放頁(yè)面橫豎屏切換。
常規(guī)實(shí)現(xiàn)方式的弊端
提到支持橫豎屏,大家可能會(huì)想到在xcode項(xiàng)目配置中,勾選landscape兩個(gè)選項(xiàng)。在項(xiàng)目中用代碼控制頁(yè)面的橫豎屏。這種方案有這么幾個(gè)缺點(diǎn):
- 需要在自定義的tabbarController和navigationController,甚至每個(gè)VC中寫控制代碼
- 在plus系列手機(jī)橫屏模式下,啟動(dòng)app時(shí),簡(jiǎn)直是杯具(不信的話,你試試有道四六級(jí)app)。市面上,有很多有觀看課程功能的app都有此類問(wèn)題。
- ......
思考過(guò)程
前段時(shí)間,我在項(xiàng)目中也遇到這個(gè)問(wèn)題。由于當(dāng)時(shí)項(xiàng)目緊,沒(méi)來(lái)的及記錄?,F(xiàn)將實(shí)現(xiàn)方案記錄下:
1. 既然以上方案存在幾個(gè)問(wèn)題,并且不好解決,那絕不能在xcode中配置橫屏。我們知道屏幕橫豎切換時(shí),會(huì)執(zhí)行AppDelegate的application:supportedInterfaceOrientationsForWindow:,返回支持的屏幕方向。那應(yīng)該在這里做操作。
2.由1又產(chǎn)生了兩條思路:
- 當(dāng)?shù)叫枰獧M屏的vc時(shí),在keywindow最頂層加個(gè)特殊命名的view。在此方法中,取出keywindow第一個(gè)view。判斷。返回橫屏還是豎屏。
- 當(dāng)需要橫屏的vc對(duì)象存在時(shí),和銷毀時(shí),在此方法做操作。
我都試了一遍,還是第二種好點(diǎn)。感興趣的同學(xué)可以試試第一種,有問(wèn)題可以留言討論。
3.將2的思路做優(yōu)化。應(yīng)該寫個(gè)工具類,hook此方法,做操作。
代碼實(shí)現(xiàn)
繼承自NSObject創(chuàng)建WSLandscapeTool工具類。代碼中有注釋,不再做說(shuō)明。
WSLandscapeTool.h
#import <UIKit/UIKit.h>
@interface WSLandscapeTool : NSObject
/**
* 在需要橫屏的控制器中調(diào)用此方法。
使用前,請(qǐng)先在AppDelegate.m中實(shí)現(xiàn)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 {
//防止循環(huán)引用
__weak typeof(UIViewController *) weakVC = needLandscapeVC;
//方法原始的實(shí)現(xiàn)
IMP originalIMP = method_getImplementation(class_getInstanceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:)));
//被替換后的新實(shí)現(xiàn)
IMP newIMP = imp_implementationWithBlock(^(id obj, UIApplication *application, UIWindow *window){
if (!weakVC) {
//VC被釋放后,把原來(lái)的方法替換回去
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
注意
方法聲明中也寫了說(shuō)明,重復(fù)下。使用工具時(shí),需要在AppDelegate.m中實(shí)現(xiàn)下supportedInterfaceOrientationsForWindow方法。
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskPortrait;
}
最后
個(gè)人見(jiàn)解,如有不妥或不明之處,請(qǐng)留言討論!謝謝!
這是Demo地址