關(guān)于iOS橫豎屏適配

關(guān)于橫豎屏適配,有一句說(shuō)一句,坑挺深的。之前做Vision和畢設(shè)的時(shí)候就處理過(guò)橫豎屏問(wèn)題,不過(guò)當(dāng)時(shí)的功力太淺,明顯沒有處理明白。所以這次在公司項(xiàng)目中又一次遇到了這種橫豎屏的需求,自然要認(rèn)真的搞一哈,順便總結(jié)一下分享給大家。其實(shí)在我理解上,只要明白以下幾點(diǎn),橫豎屏處理上并不是問(wèn)題。大家按需跳轉(zhuǎn)吧:

1.橫豎屏方向枚舉

2.開啟橫豎屏權(quán)限

3.在VC中如何開啟橫豎屏

4.橫豎屏控制優(yōu)先級(jí)

5.橫豎屏適配

6.總結(jié)

1.橫豎屏方向枚舉

關(guān)于橫豎屏一共有三種枚舉,UIInterfaceOrientation,UIInterfaceOrientationMask,UIDeviceOrientation。

1.1 UIInterfaceOrientation與UIDeviceOrientation

為什么這兩個(gè)放在一起說(shuō),好吧,你看看下面這個(gè)枚舉定義:

typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
}

我相信你應(yīng)該看出了點(diǎn)東西了把,對(duì)于iOS設(shè)備來(lái)講,屏幕狀態(tài)由以上五種狀態(tài)。上下翻轉(zhuǎn)還是很好區(qū)分的,左右旋轉(zhuǎn)可能就不是很好區(qū)分。

這里有個(gè)坑?。。?/strong>
高能預(yù)警:
請(qǐng)仔細(xì)觀察上面的枚舉值。

在處于豎屏和上下翻轉(zhuǎn)的狀態(tài)下這兩個(gè)枚舉值是一樣的,而當(dāng)處于橫屏?xí)r,這兩個(gè)值剛好相反。

所以在有時(shí)你發(fā)現(xiàn)跟你預(yù)期的翻轉(zhuǎn)方向不一樣的時(shí)候,可能你用錯(cuò)了枚舉。

UIDeviceOrientation 是設(shè)備的當(dāng)前所處的方向,而且事實(shí)上它有6個(gè)值,

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
    UIDeviceOrientationUnknown,
    UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
    UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
    UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
    UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
    UIDeviceOrientationFaceUp,              // Device oriented flat, face up
    UIDeviceOrientationFaceDown             // Device oriented flat, face down
}

分別對(duì)應(yīng)iPhone未知方向,豎直,上下反轉(zhuǎn),向左旋轉(zhuǎn),向右旋轉(zhuǎn),屏幕朝上,屏幕朝下。關(guān)于橫屏如何去分左右,其實(shí)API中的注釋已經(jīng)說(shuō)明,當(dāng)處于UIDeviceOrientationLandscapeLeft,home鍵在右側(cè),當(dāng)處于UIDeviceOrientationLandscapeRight,home鍵在左側(cè)。

所以,UIDevice顧名思義,事實(shí)上是用來(lái)判斷設(shè)備方向的。

UIInterfaceOrientation 即當(dāng)前頁(yè)面的方向。

在設(shè)備進(jìn)行橫屏旋轉(zhuǎn)的時(shí)候,為了橫屏?xí)r上下不翻轉(zhuǎn),所以當(dāng)Device處于Left時(shí),界面應(yīng)該是Right旋轉(zhuǎn)。這樣才不會(huì)使橫屏?xí)r內(nèi)容上下翻轉(zhuǎn)。所以我想你應(yīng)該明白了為什么在處于橫屏?xí)r為什么他們倆的值是剛好相反的。

所以對(duì)于橫豎屏適配,使用的枚舉大家一定要看好,使用UIInterfaceOrientation。不要搞反。

1.2 UIInterfaceOrientationMask

其實(shí)蘋果大大還是給了我們更清晰和方便的枚舉如下:

typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {
    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
}

事實(shí)上我們?cè)跈M豎屏適配時(shí),最常用的是這個(gè)枚舉。這個(gè)枚舉詳細(xì)的列舉了各種你需要的情況。我就不贅述了。官方的命名還是很舒服很好理解的。

2.開啟橫豎屏權(quán)限

開啟橫豎屏的方式有兩種,一種是在項(xiàng)目中直接進(jìn)行勾選,

image 1

可以看到這種勾選方式允許你進(jìn)行四個(gè)方向的配置,并且這種勾選方式會(huì)直接在你的項(xiàng)目plist文件中添加

image 2

但是由于在這里配置是對(duì)項(xiàng)目啟動(dòng)時(shí)lanuch界面產(chǎn)生影響,而往往我們又沒有對(duì)lanuch進(jìn)行橫豎屏適配,所以在這個(gè)時(shí)候我們就需要使用第二種方式進(jìn)行配置。

在項(xiàng)目中的AppDelegate文件中進(jìn)行配置。

#pragma mark - InterfaceOrientation //應(yīng)用支持的方向
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

搭配UIInterfaceOrientationMask使用,你可以很方便的讓你項(xiàng)目開啟你所需要的橫豎屏權(quán)限和限制條件。

3.在VC中如何控制橫豎屏

我們都知道MVC架構(gòu),那么顯而易見,在我們開啟了項(xiàng)目的橫豎屏的限制之后,需要在ViewController進(jìn)行相應(yīng)的配置,才能真正實(shí)現(xiàn)橫豎屏。

開啟橫豎屏,我們需要在VC中添加如下代碼:

// 設(shè)備支持方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}
// 默認(rèn)方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationPortrait; // 或者其他值 balabala~
}

而對(duì)于橫豎屏,手機(jī)端一般有兩種情況,一種是手機(jī)沒有開啟橫豎屏鎖定,用戶將手機(jī)橫屏?xí)r觸發(fā)的。對(duì)于第一種情況,我們只需要在VC中添加:

// 開啟自動(dòng)轉(zhuǎn)屏
- (BOOL)shouldAutorotate {
    return YES;
}

另一種是我們?cè)陧?xiàng)目中的某些條件下強(qiáng)行讓屏幕橫屏,例如大圖預(yù)覽,視頻播放,等等。而對(duì)于這種情況,我們可以使用下面??這兩種方法,都可以實(shí)現(xiàn)效果:

- (void)setInterfaceOrientation:(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];
    }
}

- (void)setInterfaceOrientation:(UIDeviceOrientation)orientation {
    if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
        [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:orientation] forKey:@"orientation"];
    }
}

PS:這兩個(gè)方法只有在- (BOOL)shouldAutorotate( return YES; )時(shí),才會(huì)生效。并且請(qǐng)注意使用的枚舉值的不同。

4.橫豎屏控制優(yōu)先級(jí)

在我們接手一個(gè)項(xiàng)目后,說(shuō)要添加一個(gè)某個(gè)界面橫豎屏需求時(shí),發(fā)現(xiàn)按照上面的方式配置了一圈,發(fā)現(xiàn)還是轉(zhuǎn)!不!成!功!What F***?。。?/p>

事實(shí)上在這里我們要了解一個(gè)問(wèn)題,就是關(guān)于橫豎屏控制的優(yōu)先級(jí)。對(duì)于限于VC范圍來(lái)講優(yōu)先級(jí)最高的是當(dāng)前的windowrootViewController,而往往我們的項(xiàng)目結(jié)構(gòu)是容器視圖控制器控制VCtabBarController控制navigationController之后是VC,而橫豎屏控制的優(yōu)先級(jí)也是跟你的項(xiàng)目架構(gòu)一樣。而且是一旦優(yōu)先級(jí)高的關(guān)閉了橫豎屏配置,優(yōu)先級(jí)低的無(wú)論如何配置都無(wú)法做到橫豎屏。所以在你接受這個(gè)需求的時(shí)候,你需要看一下根視圖的配置。

對(duì)于這種情況,我們有兩種處理方式,一種是通過(guò)模態(tài)的方式跳轉(zhuǎn)的下個(gè)VC,這個(gè)VC是隔離出來(lái)的,不在你之前的容器里,不會(huì)受到rootViewController的影響。

而另一種我們需要改造一下根視圖的配置:

-(BOOL)shouldAutorotate {  
    return [[self.viewControllers lastObject] shouldAutorotate];  
}  

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {  
     return [[self.viewControllers lastObject] supportedInterfaceOrientations];  
}  

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {  
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];  
}

或者

-(BOOL)shouldAutorotate {
    if ([[self.viewControllers lastObject]isKindOfClass:[NewViewController class]]) {
        return YES;
    }
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    if ([[self.viewControllers lastObject]isKindOfClass:[NewViewController class]]) {
        return UIInterfaceOrientationMaskLandscapeLeft;
    }
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    if ([[self.viewControllers lastObject]isKindOfClass:[NewViewController class]]) {
        return UIInterfaceOrientationLandscapeLeft;
    }
    return UIInterfaceOrientationPortrait;
}

可以看到我們通過(guò)獲取push棧中的最后一個(gè)VC的屬性,或指定特殊的VC來(lái)進(jìn)行rootViewController的橫豎屏設(shè)置。

當(dāng)然也可以通過(guò)NSNotificationCenter或者NSUserDefaults的方式對(duì)這里的值進(jìn)行設(shè)置,在這里我就不過(guò)多贅述了。

總之要知道優(yōu)先級(jí)的問(wèn)題,general == appDelegate >> rootViewController >> nomalViewController

明白了權(quán)限的優(yōu)先級(jí)以及開啟的方法我想轉(zhuǎn)屏就很顯而易見了。

5.橫豎屏適配

事實(shí)上旋轉(zhuǎn)屏幕成功,對(duì)于iOS橫豎屏問(wèn)題我們只是完成了一半。另一半就是UI適配問(wèn)題,其實(shí)這個(gè)要說(shuō)起來(lái)就比較麻煩了,有些時(shí)候有很多case需要針對(duì)對(duì)應(yīng)的業(yè)務(wù)條件來(lái)定制。但是無(wú)外乎幾種實(shí)現(xiàn)思路。這里博主給大家拋幾塊磚哈:

首先我們要知道,當(dāng)發(fā)生轉(zhuǎn)屏事件時(shí),系統(tǒng)的回調(diào)方法是:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    
    if (size.width > size.height) { // 橫屏
        // 橫屏布局 balabala
    } else {
        // 豎屏布局 balabala
    }
}

首推的方式是使用約束布局,在使用約束布局時(shí),橫豎屏轉(zhuǎn)換時(shí),在通常情況下約束條件會(huì)很相似,所以在布局上會(huì)極大的減少代碼量。其次如果有個(gè)別的特殊問(wèn)題,可以在上面的回調(diào)方法里面進(jìn)行微調(diào)。

其次,對(duì)于轉(zhuǎn)屏后,[UIScreen mainScreen].bounds.size以及self.view.frame.size的寬高系統(tǒng)會(huì)自動(dòng)調(diào)換。即在橫屏的時(shí)候width > height。所以在我們進(jìn)行常規(guī)布局的時(shí)候我們可以選擇控件的frame屬性都與這兩個(gè)屬性進(jìn)行比例換算。這樣在當(dāng)橫豎屏轉(zhuǎn)換的時(shí)候,重布局時(shí),也會(huì)適應(yīng)成對(duì)應(yīng)屏幕下的布局。同樣有需要特殊處理的布局,在上面的回調(diào)方法中進(jìn)行細(xì)節(jié)微調(diào)即可。

對(duì)于子視圖,在橫豎屏切換時(shí),會(huì)觸發(fā)子視圖重布局的方法:

- (void)layoutSubviews {
    [super layoutSubviews];
    // 通過(guò)狀態(tài)欄電池圖標(biāo)來(lái)判斷屏幕方向
    if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationMaskPortrait) {
        // 豎屏 balabala
    } else {
        // 橫屏 balabala
    }
}

當(dāng)然我只是說(shuō)了幾種比較簡(jiǎn)單的處理方式,和應(yīng)對(duì)方法,對(duì)于整個(gè)項(xiàng)目都需要橫豎屏適配的,我想還是一個(gè)比較復(fù)雜的過(guò)程。在實(shí)在處理不了的問(wèn)題上,也可以通過(guò)寫兩套布局的方式來(lái)處理。至于過(guò)場(chǎng)動(dòng)畫,理論上如果你用約束和我說(shuō)的比例布局的方式來(lái)寫,基本系統(tǒng)會(huì)自動(dòng)幫你這個(gè)問(wèn)題給處理掉。但如果兩種布局差距很大,你用了兩套完全不同的布局,那這個(gè)你可能就要傷腦筋了。哈哈哈。不過(guò)有一些情況處理要求不嚴(yán)格的話可以使用截圖過(guò)場(chǎng)大法來(lái)解決。不過(guò)這個(gè)就不是本文的設(shè)計(jì)范圍了。大家如果感興趣可以自己google一下。當(dāng)然我日后的文章也可能會(huì)寫到這了。到時(shí)候再來(lái)這里修改。

6.總結(jié)

iOS橫豎屏適配,確實(shí)有很多坑,當(dāng)然,有些坑是系統(tǒng)的;而有些坑,是因?yàn)槲覀兊臒o(wú)知而造成的。所以多看多學(xué)多做多理解,必然能讓你學(xué)到更多,增強(qiáng)填坑的硬實(shí)力。而對(duì)于橫豎屏適配這塊,轉(zhuǎn)屏并不難,難的是橫豎屏布局適配。博主只是簡(jiǎn)單的說(shuō)了一些思路,至于實(shí)現(xiàn)起來(lái),還是要針對(duì)對(duì)應(yīng)的需求來(lái)進(jìn)行處理。下面??給大家鏈接幾個(gè)博主覺得還不錯(cuò)的關(guān)于適配的文章,大家可以看看:

iPad橫豎屏下的代碼適配

iOS 屏幕適配,autoResizing autoLayout和sizeClass圖文詳解

博主私人博客@HarwordLiu

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,697評(píng)論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,182評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,406評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,772評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,973評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評(píng)論 1 285
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,644評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,953評(píng)論 2 373

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,151評(píng)論 4 61
  • 1.尺寸適配1.原因 iOS7中所有導(dǎo)航欄都為半透明,導(dǎo)航欄(height=44)和狀態(tài)欄(height=20)不...
    LZM輪回閱讀 6,133評(píng)論 1 4
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,636評(píng)論 25 708
  • 早上很早就去學(xué)校,放學(xué)故意在學(xué)校耽擱很久才走,駱月不再和秦空一起上下學(xué)了。 駱月這才發(fā)現(xiàn),如果不是她主動(dòng)靠近,即使...
    寧我閱讀 301評(píng)論 0 1
  • 好妹妹樂隊(duì)有一首歌 我到外地去看你 “最后我們沒有在一起 沒有在一起 好在我們已反復(fù)練習(xí) 習(xí)慣了別離 抱歉我所有...
    MeredithY閱讀 401評(píng)論 0 0