iOS屏幕旋轉解決方案

1.導航控制器棧內(nèi)部的VC方向是導航控制器來決定的瓜客。nav --- A --- B --- C,C的旋轉方法是不起作用的殊霞,靠的是nav的-(BOOL)shouldAutorotate-(UIInterfaceOrientationMask)supportedInterfaceOrientations粉私。

解決方案是:重寫nav的旋轉方法绷旗,把結果指向到topViewController:

-(BOOL)shouldAutorotate{
   return self.topViewController.shouldAutorotate;
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return self.topViewController.supportedInterfaceOrientations;
}

對于UITabBarController,就轉嫁為它的selectedViewController的結果肘习。

2.旋轉的邏輯流是:手機方向改變了 ---> 通知APP ---> 調用APP內(nèi)部的關鍵VC(TabBar或Nav)的旋轉方法 ---> 得到可旋轉并且支持當前設備方向 ---> 旋轉到指定方向际乘。

邏輯流的初始時物理上手機方向改變了。所有如果A push到 B井厌,A只支持豎屏蚓庭,而B只支持橫屏,如果這時手機物理方向沒變仅仆,那么B還是會跟A一樣豎屏,哪怕它只支持橫屏并且問題1也解決了的垢袱。

解決方案:強制旋轉墓拜。

@implementation UIDevice (changeOrientation)

+ (void)changeInterfaceOrientationTo:(UIInterfaceOrientation)orientation
{
   if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
       SEL selector             = NSSelectorFromString(@"setOrientation:");
       NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
       [invocation setSelector:selector];
       [invocation setTarget:[UIDevice currentDevice]];
       int val                  = orientation;
       [invocation setArgument:&val atIndex:2];
       [invocation invoke];
   }
}


@end

UIDevice提供一個category,調用setOrientation:這個私有方法來實現(xiàn)请契。

3.有了問題1和2的解決咳榜,對于整個項目的基本方案確定。一般項目會有一個主方向爽锥,絕大多數(shù)界面都是這個方向涌韩,比如豎屏,然后有特定界面是特定方向氯夷。

那么解決方案是:

  • 在target --> General --> Development Info里配置支持所有可能的方向
  • 使用baseViewController臣樱,項目所有VC都繼承與它,在baseVC里寫入默認方向設置腮考,這個默認設置就是絕大多數(shù)界面支持的方向雇毫。
  • 然后在特殊方向界面,重寫-(BOOL)shouldAutorotate-(UIInterfaceOrientationMask)supportedInterfaceOrientations來達到自己的目的踩蔚。
  • 特殊界面因為要強制旋轉棚放,所以在進入界面是旋轉到需要方向:
  -(void)viewWillAppear:(BOOL)animated{
   [UIDevice changeInterfaceOrientationTo:(UIInterfaceOrientationLandscapeLeft)];
}
4.push和pop的結果測試:

要驗證問題3的方案是否滿足需要,滿足需要的意思是:每個頁面能夠顯示它支持的方向而且不會干擾到其他界面馅闽。所以測試一下push和pop的情況飘蚯。

測試變量有:

  • 當前的界面是默認還是特殊馍迄,這里把只有豎屏設為默認绞佩,橫屏為特殊情況应结。默認代表這個VC只需繼承baseVC的方向相關方法攘轩,不做任何額外處理厚脉。
  • 界面是push還是pop
  • 下一個界面是默認情況還是特殊情況蓄愁。
  • 下一個界面的shouldAutorate是否為YES暮胧。

前后兩個界面方向一致的畫好唯,結果肯定是好的鞋诗,就不測試 了穴店。最終測試結果如下:

動作 當前 目標 目標可旋轉 結果
push 默認 特殊 ?? 成功
push 默認 特殊 ? 失敗
push 特殊 默認 ?? 失敗(2)
push 特殊 默認 ? 失敗(3)
pop 默認 特殊 ?? 成功
pop 默認 特殊 ? 失敗
pop 特殊 默認 ?? 成功(1)
pop 特殊 默認 ? 成功(1)
  • 成功代表目標界面旋轉到了期望的方向
  • 標記1:沒有旋轉撕捍,直接顯示的默認樣式(豎屏)。
  • 標記2:從橫屏到豎屏泣洞,沒有切換方向忧风,為什么?因為UIDevice的方向沒有修改球凰,沒有觸發(fā)切換效果狮腿。所以在特殊界面離開的時候還要調用強制旋轉。其實只要相鄰的方向不同呕诉,就要在切換時觸發(fā)強制旋轉缘厢。
  • 添加了viewWillDisappear里的強制旋轉后,標記2可以解決甩挫。但標記3還是失敗贴硫,其實push時,下一個界面如果是不可旋轉的伊者,那么方向一定是不變了英遭。

特殊界面只要保持,進入和離開時都調用強制旋轉亦渗,并且自身shouldAutorate為YES,那么push或pop進入特殊界面都沒有問題挖诸。關鍵是從特殊界面離開進入默認界面,pop時是成功的法精,push時如果默認界面是不可旋轉的多律,就會失敗。

針對這個有兩種方案:

  • 在離開前把當前界面旋轉為默認亿虽,先旋轉菱涤,再push。
  • 把默認界面改為可旋轉洛勉。
5.特殊方向界面離開前先旋轉到默認

因為特殊界面支持的方向不包含默認方向粘秆,所以只是強制旋轉時不起作用的,在強制旋轉前還要修改支持的方向收毫。具體代碼:

- (IBAction)push:(id)sender {
   
   [self changeOrientationBeforeDisappear];  //離開前先修改方向攻走,其他每個出口都要調用這個方法殷勘。不能在`viewWillDisappear`里調用,因為這時push等已經(jīng)觸發(fā)了
   TFThirdViewController *thirdVC = [[TFThirdViewController alloc] init];
   [self.navigationController pushViewController:thirdVC animated:YES];
}

-(void)changeOrientationBeforeDisappear{
   _orientation = UIInterfaceOrientationMaskPortrait;  //替換為默認方向
   [UIDevice changeInterfaceOrientationTo:(UIInterfaceOrientationPortrait)];
   _orientation = UIInterfaceOrientationMaskLandscapeLeft; //替換為特殊方向界面自身需要的方向
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
   return _orientation;  //根據(jù)變量變化而變化
}

如果下一個界面不是默認昔搂,會是什么情況玲销?會有兩次旋轉。離開時旋轉到默認摘符,進入下一個界面贤斜,它自身又旋轉到指定方向。效果不好逛裤,如果想一次到位瘩绒,怎么辦?就要離開的時候知道下一個界面期望的方向是什么带族,然后preferredInterfaceOrientationForPresentation正好符合這個意圖锁荔。
所以修改為:

@interface TFSecondViewController (){
   UIInterfaceOrientationMask _orientation;
   UIInterfaceOrientationMask _needOrientation;
}

@end

@implementation TFSecondViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   
   _needOrientation = UIInterfaceOrientationMaskLandscapeLeft;
   _orientation = _needOrientation;
}

-(void)viewWillAppear:(BOOL)animated{
   [UIDevice changeInterfaceOrientationTo:(UIInterfaceOrientationLandscapeLeft)];
}

-(BOOL)shouldAutorotate{
   return YES;
}

- (IBAction)push:(id)sender {
   
   TFThirdViewController *thirdVC = [[TFThirdViewController alloc] init];
   [self changeOrientationBeforeDisappearTo:thirdVC];  //離開前先修改方向,其他每個出口都要調用這個方法蝙砌。不能在`viewWillDisappear`里調用阳堕,因為這時push等已經(jīng)觸發(fā)了
   
   [self.navigationController pushViewController:thirdVC animated:YES];
}

-(void)changeOrientationBeforeDisappearTo:(UIViewController *)nextVC{
   _orientation = UIInterfaceOrientationMaskAll;  //改為任意方向
   [UIDevice changeInterfaceOrientationTo:[nextVC preferredInterfaceOrientationForPresentation]];
   _orientation = _needOrientation; //替換為特殊方向界面自身需要的方向
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
   return _orientation;  //根據(jù)變量變化而變化
}

@end

_needOrientation時當前頁面需要的樣式。

總結起來就是:

  • 給絕大多數(shù)情況建一個baseVC,里面設置默認方向择克。
  • 對特殊方向界面:
    • 進入時(viewWillAppear)強制旋轉到需要的方向
    • 離開時恬总,注意并不是viewWillDisappear,而是push操作之前,先修改方向為下一個界面的期望方向祠饺。
    • 當然自身的shouldAutorotate保持為YES越驻。
  • 方向相關的3個方法全部要實現(xiàn)。因為基類(BaseVC)做了處理道偷,可以省去絕大部分的工作。特殊方向的界面單個處理即可记劈。
  • preferredInterfaceOrientationForPresentation的方向要和進入時的方向一致勺鸦,這樣就不會有2次旋轉。

相比把基類的shouldAutorotate改為YES,這個方案的好處是目木,把特殊情況的處理基本都壓縮在特殊界面自身內(nèi)部了换途,依賴的只有其他界面的supportedInterfaceOrientations,這個方法是一個補充性的,不會干擾其他界面原本的設計刽射。而對shouldAutorotate卻比較麻煩军拟,因為其他界面可能不希望旋轉。

再次測試pop和push情況:

動作 當前 目標 目標可旋轉 結果
push 默認 特殊 ?? 成功
push 特殊 默認 ?? 成功
push 特殊 默認 ? 成功
pop 默認 特殊 ?? 成功
pop 特殊 默認 ?? 成功
pop 特殊 默認 ? 成功
push 特殊1 特殊2 ?? 成功
pop 特殊1 默認2 ?? 成功
  • 特殊的都是可旋轉的誓禁,所以這種情況剔除了
6.present和dismiss的情況
動作 當前 目標 目標可旋轉 結果
present 默認 特殊 ?? 奔潰(1)
present 特殊 默認 ?? 成功
present 特殊 默認 ? 成功
dismiss 默認 特殊 ?? 成功
dismiss 特殊 默認 ?? 成功
dismiss 特殊 默認 ? 成功
present 特殊1 特殊2 ?? 成功
dismiss 特殊1 默認2 ?? 成功

奔潰1的問題是因為沒有實現(xiàn)preferredInterfaceOrientationForPresentation,而默認結果是當前的statusBar的樣式懈息,從默認過去,那就是豎直方向摹恰,而這個界面supportedInterfaceOrientations的樣式又是橫屏辫继,所以優(yōu)先的方向(preferredxxx)不包含在支持的方向(supportedxxx)里就奔潰了怒见。按照之前的約定,supportedInterfaceOrientations是必須實現(xiàn)的姑宽,實現(xiàn)了就成功了遣耍。

所以解決方案通過測試。

最后炮车,present和push的切換方式有個不同:如果A--->B使用present方式舵变,A不可旋轉,但同時支持橫豎屏瘦穆,B可旋轉纪隙,支持橫豎屏,那么 A豎屏 ---> B豎屏 ---> 旋轉到橫屏 ---> dismiss 這個流程后难审,A會變成橫屏且不可旋轉瘫拣。

也就是dismiss時,返回的界面不看你能不能旋轉告喊,如果你支持當前的方向麸拄,就會直接變成當前方向的樣式。而supportedInterfaceOrientations默認是3個方向的黔姜,所以不實現(xiàn)這個方法而使用默認的拢切,在dismiss的時候會有坑。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秆吵,一起剝皮案震驚了整個濱河市淮椰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纳寂,老刑警劉巖主穗,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異毙芜,居然都是意外死亡忽媒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門腋粥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晦雨,“玉大人,你說我怎么就攤上這事隘冲∧智疲” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵展辞,是天一觀的道長奥邮。 經(jīng)常有香客問我,道長纵竖,這世上最難降的妖魔是什么漠烧? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任杏愤,我火速辦了婚禮,結果婚禮上已脓,老公的妹妹穿的比我還像新娘珊楼。我一直安慰自己,他們只是感情好度液,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布厕宗。 她就那樣靜靜地躺著,像睡著了一般堕担。 火紅的嫁衣襯著肌膚如雪已慢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天霹购,我揣著相機與錄音佑惠,去河邊找鬼。 笑死齐疙,一個胖子當著我的面吹牛膜楷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贞奋,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼赌厅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了轿塔?” 一聲冷哼從身側響起特愿,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勾缭,沒想到半個月后揍障,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡俩由,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年亚兄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片采驻。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖匈勋,靈堂內(nèi)的尸體忽然破棺而出礼旅,到底是詐尸還是另有隱情,我是刑警寧澤洽洁,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布痘系,位于F島的核電站,受9級特大地震影響饿自,放射性物質發(fā)生泄漏汰翠。R本人自食惡果不足惜龄坪,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望复唤。 院中可真熱鬧健田,春花似錦、人聲如沸佛纫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呈宇。三九已至好爬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甥啄,已是汗流浹背存炮。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蜈漓,地道東北人穆桂。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像迎变,于是被迫代替她去往敵國和親充尉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

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