前言
在iOS開發(fā)中,如果APP需要支持橫屏弓熏,就要控制頁面旋轉(zhuǎn)恋谭,但是讓頁面支持旋轉(zhuǎn)的方式有很多糠睡,在此總結(jié)一下挽鞠,說一下我對頁面旋轉(zhuǎn)的理解。
思路
控制頁面旋轉(zhuǎn)的方式可以總結(jié)為兩種,第一種是通過全局設(shè)置來控制信认,第二種是頁面自己單獨控制材义。
1.修改全局設(shè)置來實現(xiàn)
第一種是通過勾選方向讓頁面支持旋轉(zhuǎn)。
第二種是通過修改info.plist文件
Supported interface orientations
設(shè)置選項嫁赏,增加方向讓頁面支持旋轉(zhuǎn)其掂。
第三種是通過在
AppDelegate
中實現(xiàn)- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
方法讓頁面支持旋轉(zhuǎn)。
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
//返回你需要的方向
return UIInterfaceOrientationMaskPortrait;
}
這三種方式種潦蝇,前面兩種是一樣的款熬,需要注意的是第三種方式,它的優(yōu)先級是最高的攘乒,也就是你通過AppDelegate
這種方式來控制全局旋轉(zhuǎn)贤牛,同時勾選或者修改了plist選項,最終會以AppDelegate
中支持的方向為準(zhǔn)则酝。
全局控制這種方式殉簸,通常用在所有頁面都需要支持全屏的情況下,如果要讓某個頁面支持沽讹,大部分頁面不支持般卑,又該怎么處理呢?在這里利用runtime動態(tài)替換方法和分類的特性爽雄,來實現(xiàn)單獨控制頁面旋轉(zhuǎn)蝠检,經(jīng)過封裝后,一句話就可以達到讓頁面支持或者不支持旋轉(zhuǎn)盲链。
代碼
AppDelegate分類代碼中實現(xiàn)- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
方法蝇率,利用分類的特性來完成AppDelegate
需要實現(xiàn)的代碼
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
//返回你需要的方向
return UIInterfaceOrientationMaskPortrait;
}
UIViewController
分類中利用runtime
動態(tài)替換方法實現(xiàn)控制頁面旋轉(zhuǎn)习寸,這里使用week是因為頁面銷毀的時候需要將其他控制器的方向還原恼布,不被當(dāng)前頁面修改方向后影響。
- (void)isNeedRotation:(BOOL)needRotation{
AppDelegate * appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
__weak __typeof(self) weakSelf = self;
IMP originalIMP = method_getImplementation(class_getInstanceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:)));
IMP newIMP = imp_implementationWithBlock(^(id obj, UIApplication *application, UIWindow *window){
if (!weakSelf) {
class_replaceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:), originalIMP, method_getTypeEncoding(class_getInstanceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:))));
}
return needRotation ? UIInterfaceOrientationMaskAll : UIInterfaceOrientationMaskPortrait;
});
class_replaceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:), newIMP, method_getTypeEncoding(class_getInstanceMethod([appDelegate class], @selector(application:supportedInterfaceOrientationsForWindow:))));
}
2.通過每個頁面單獨控制頁面旋轉(zhuǎn)
通過每個頁面單獨控制頁面旋轉(zhuǎn)膘婶,首先必須打開全局方向設(shè)置侧漓,設(shè)置需要旋轉(zhuǎn)的方向锅尘,然后根據(jù)頁面不同的創(chuàng)建方式(push或者present)和不同根控制器(UITabBarController
或者UINavigationController
),可以分出三種情況布蔗。
第一種情況藤违,頁面通過UINavigationController
+push創(chuàng)建,在這種情況下纵揍,需要在UINavigationController
實現(xiàn)以下方法就可以使頁面支持旋轉(zhuǎn)顿乒。
// 是否支持自動轉(zhuǎn)屏
- (BOOL)shouldAutorotate {
return [self.topViewController shouldAutorotate];
}
// 支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return [self.topViewController supportedInterfaceOrientations];
}
第二種情況,頁面通過UITabBarController
+push創(chuàng)建泽谨,在這種情況下璧榄,需要在UITabBarController
特漩,UINavigationController
都實現(xiàn)以下方法才可以讓頁面支持旋轉(zhuǎn)。其中需要注意的是UITabBarController
中骨杂,需要利用runtime
動態(tài)替換系統(tǒng)方法涂身,防止沒有初始值造成越界。
+ (void)load {
SEL selectors[] = {
@selector(selectedIndex)
};
for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
SEL originalSelector = selectors[index];
SEL swizzledSelector = NSSelectorFromString([@"cl_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
Method originalMethod = class_getInstanceMethod(self, originalSelector);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
if (class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
}
- (NSInteger)cl_selectedIndex {
NSInteger index = [self cl_selectedIndex];
if (index > self.viewControllers.count){
return 0;
}else{
return index;
}
}
- (BOOL)shouldAutorotate {
return [self.selectedViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.selectedViewController supportedInterfaceOrientations];
}
第三種情況搓蚪,頁面通過present創(chuàng)建蛤售,需要在present出來的頁面實現(xiàn)以下方法才可以讓頁面支持旋轉(zhuǎn)。
// 是否支持自動轉(zhuǎn)屏
- (BOOL)shouldAutorotate {
return NO;
}
// 支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
// 默認(rèn)的屏幕方向(當(dāng)前ViewController必須是通過模態(tài)出來的UIViewController(模態(tài)帶導(dǎo)航的無效)方式展現(xiàn)出來的妒潭,才會調(diào)用這個方法)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
頁面自己單獨控制旋轉(zhuǎn)悴能,需要每個頁面都寫重復(fù)的代碼,很多時候都是利用基類來實現(xiàn)雳灾,但是需要子頁面繼承搜骡,對代碼還是有一定的影響。既不想寫基類佑女,又不想每個頁面單獨寫代碼记靡,又該怎么來實現(xiàn)呢?在這里還是利用分類的特性团驱,分別創(chuàng)建UITabBarController
摸吠,UINavigationController
,UIViewController
的分類來實現(xiàn)嚎花。
代碼
UITabBarController
分類中的代碼寸痢。
// 是否支持自動轉(zhuǎn)屏
- (BOOL)shouldAutorotate {
UIViewController *vc = self.viewControllers[self.selectedIndex];
if ([vc isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)vc;
return [nav.topViewController shouldAutorotate];
} else {
return [vc shouldAutorotate];
}
}
// 支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
UIViewController *vc = self.viewControllers[self.selectedIndex];
if ([vc isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)vc;
return [nav.topViewController supportedInterfaceOrientations];
} else {
return [vc supportedInterfaceOrientations];
}
}
// 默認(rèn)的屏幕方向(當(dāng)前ViewController必須是通過模態(tài)出來的UIViewController(模態(tài)帶導(dǎo)航的無效)方式展現(xiàn)出來的,才會調(diào)用這個方法)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
UIViewController *vc = self.viewControllers[self.selectedIndex];
if ([vc isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)vc;
return [nav.topViewController preferredInterfaceOrientationForPresentation];
} else {
return [vc preferredInterfaceOrientationForPresentation];
}
}
UINavigationController
分類中的代碼紊选。
// 是否支持自動轉(zhuǎn)屏
- (BOOL)shouldAutorotate {
return [self.topViewController shouldAutorotate];
}
// 支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return [self.topViewController supportedInterfaceOrientations];
}
// 默認(rèn)的屏幕方向(當(dāng)前ViewController必須是通過模態(tài)出來的UIViewController(模態(tài)帶導(dǎo)航的無效)方式展現(xiàn)出來的啼止,才會調(diào)用這個方法)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
UIViewController
分類中的代碼。
/**
* 默認(rèn)所有都不支持轉(zhuǎn)屏,如需個別頁面支持除豎屏外的其他方向兵罢,請在viewController重新下邊這三個方法
*/
// 是否支持自動轉(zhuǎn)屏
- (BOOL)shouldAutorotate {
return NO;
}
// 支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
// 默認(rèn)的屏幕方向(當(dāng)前ViewController必須是通過模態(tài)出來的UIViewController(模態(tài)帶導(dǎo)航的無效)方式展現(xiàn)出來的献烦,才會調(diào)用這個方法)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
總結(jié)
基于以上兩種情況,我都分別寫了Demo卖词,具體大家自己去看Demo巩那,如果喜歡,歡迎start Demo地址------》
CLRotationTools