iOS頁面旋轉(zhuǎn)詳解

路漫漫其修遠兮

前言

在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)其掂。

plist文件

第三種是通過在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摸吠,UINavigationControllerUIViewController的分類來實現(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末此蜈,一起剝皮案震驚了整個濱河市即横,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌裆赵,老刑警劉巖东囚,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異战授,居然都是意外死亡页藻,警方通過查閱死者的電腦和手機抛蚁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惕橙,“玉大人,你說我怎么就攤上這事钉跷∶逐校” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵爷辙,是天一觀的道長彬坏。 經(jīng)常有香客問我,道長膝晾,這世上最難降的妖魔是什么栓始? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮血当,結(jié)果婚禮上幻赚,老公的妹妹穿的比我還像新娘。我一直安慰自己臊旭,他們只是感情好落恼,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著离熏,像睡著了一般佳谦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滋戳,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天钻蔑,我揣著相機與錄音,去河邊找鬼奸鸯。 笑死咪笑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的娄涩。 我是一名探鬼主播蒲肋,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼钝满,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弯蚜?” 一聲冷哼從身側(cè)響起碎捺,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晋柱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钦椭,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡彪腔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年进栽,在試婚紗的時候發(fā)現(xiàn)自己被綠了快毛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡吗浩,死狀恐怖没隘,靈堂內(nèi)的尸體忽然破棺而出右蒲,到底是詐尸還是另有隱情,我是刑警寧澤陷嘴,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布灾挨,位于F島的核電站竹宋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏秒拔。R本人自食惡果不足惜砂缩,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一庵芭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧眨唬,春花似錦伊诵、人聲如沸曹宴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至礁芦,卻和暖如春悼尾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背未状。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工司草, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泡仗,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像峦树,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子急灭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容