iOS-屏幕適配實(shí)現(xiàn)(AutoLayout)

AutoLayout簡(jiǎn)介

AutoLayout旨在替代Autoresizing,所以在同一個(gè)項(xiàng)目中,AutoLayout和Autoresizing是不能共存的,二者只能選其一,如果你選擇了AutoLayout,那么Autoresizing自動(dòng)被屏蔽掉;如果你選擇了Autoresizing,那么AutoLayout自動(dòng)被屏蔽掉。XCode5及其之后的版本,默認(rèn)新建的項(xiàng)目就是使用AutoLayout


關(guān)于約束

約束概念

AutoLayout主要是通過控件參照與約束實(shí)現(xiàn),比如控件A相對(duì)控件B來說,控件A在控件B的正下方,間距為20px

每在xib或sb中對(duì)控件添加一個(gè)約束, 就代表添加一個(gè)約束對(duì)象。比如,給xib中的某個(gè)子控件A設(shè)置了寬度和高度、距離父控件上下左右之間的間距,就相當(dāng)于給這個(gè)控件添加了6個(gè)約束,也就產(chǎn)生了6個(gè)約束對(duì)象

約束錯(cuò)誤警告

  • 紅色箭頭,代表約束錯(cuò)誤,一般是缺少約束或約束沖突(例如375的屏幕寬度,你不能距離左邊200,距離右邊200,還要控件寬度100,肯定不行)
  • 黃色箭頭,代表約束警告,表示當(dāng)前控件在xib中呈現(xiàn)的位置或者尺寸和程序運(yùn)行后實(shí)際呈現(xiàn)的效果不一樣,導(dǎo)致約束警告的原因往往是沒有更新控件的約束,但并不影響其真實(shí)效果,也不會(huì)報(bào)錯(cuò)

注意:約束有錯(cuò)誤,不代表運(yùn)行會(huì)錯(cuò)誤,約束錯(cuò)誤同樣可以運(yùn)行

約束的規(guī)則

  • 相對(duì)于父視圖的約束,添加到父視圖上
對(duì)于兩個(gè)同層級(jí) view 之間的約束關(guān)系,添加到它們的父 view 上
  • 相對(duì)于另一個(gè)控件的約束,添加到其共有的父視圖上

    對(duì)于兩個(gè)不同層級(jí) view 之間的約束關(guān)系,添加到他們最近的共同父 view 上

  • 跨層級(jí)的約束,添加到其最上層的父視圖上

    對(duì)于有層次關(guān)系的兩個(gè) view 之間的約束關(guān)系,添加到層次較高的父 view 上

  • 自身的寬高等約束,添加到自身視圖上

特殊控件的約束

UILabel默認(rèn)內(nèi)容的顯示方式是垂直居中的。如果用autolayout給UILabel設(shè)置約束,只需要設(shè)置x、y、width,無需設(shè)置height,UILabel會(huì)自動(dòng)包裹內(nèi)容,并且隨內(nèi)容的多小而變化。如果我們通過約束給定了UILabel的width = 100,但是內(nèi)容仍然少的可憐,不能包裹,可以把寬度設(shè)置為<=100,此時(shí),label的寬高都能包裹住內(nèi)容。高度的設(shè)置同理可證。
當(dāng)然,我們也可以只給UILabel設(shè)置x、y。但必須要保證UILabel的text屬性有內(nèi)容,否則UILabel顯示不出來(這是初學(xué)者經(jīng)常犯的錯(cuò)誤)。原因在于,UILabel是根據(jù)內(nèi)容自動(dòng)調(diào)整寬度和高度,如果沒有內(nèi)容,那么寬度和高度就是0,導(dǎo)致UILabel無法顯示。


AutoLayout用法

XIB中設(shè)置AutoLayout

  • 多個(gè)控件對(duì)齊處理

    多個(gè)控件對(duì)齊處理

  • 單個(gè)控件的處理

    單個(gè)控件的處理

    Safe Area : iOS11中增加的,safe area 可以看作是系統(tǒng)在所有的 view 上加了一個(gè)虛擬的 view, 這個(gè)虛擬的 view 的大小等都是跟 view 的位置等有關(guān)的(當(dāng)然是在 iPhoneX上才有值) 以后在寫代碼的時(shí)候,自定義的控件都盡量針對(duì) safe area 這個(gè)虛擬的 view 進(jìn)行布局

    Constrain to margins : 默認(rèn)會(huì)距邊框16px, iPhone6Pluse 準(zhǔn)備的,一般都會(huì)去掉

    User Standard Value :使用標(biāo)準(zhǔn)的的值,而且這個(gè)值只有在是設(shè)置上下方向的時(shí)候才有用。默認(rèn)的值其實(shí)就是距離 Bottom Layout Guide,也就是上下基線。下基線就是距離視圖最底部。上基線就是距離StatusView下方的位置

    User Current Canvas Value :使用當(dāng)前位置設(shè)置。默認(rèn)為當(dāng)前設(shè)置方向最近的一個(gè)VIew,且沒有覆蓋遮擋的視圖

    注意:上下左右的間距和控件的寬度、高度配合使用,盡量不要沖突; 例如:375的屏幕寬度,你不能距離左邊200,距離右邊200,還要控件寬度100,肯定不行

    建議:給了距離左邊的間距,同時(shí)給出空間寬度即可,適用于lable,textfile等控件,不考慮它到底距離右邊多少;如果給了距離左右的間距,就不要給寬度了,適用于button之類的控件。

  • 更新、添加、清除約束

    更新、添加、清除約束

    Selected Views : 處理當(dāng)前你選中View的約束問題,Clear Constraints 清除約束,會(huì)刪除選中的視圖的所有的約束

    All Views in View Controller :處理當(dāng)前ViewController里所有的View的約束問題,Clear Constraints 會(huì)刪除當(dāng)前VC所有的約束

  • 自適應(yīng)布局(Trait Variations)

    Trait Variations替換了的Size Class??梢钥吹较旅鏅C(jī)型與自適應(yīng)的尺寸匹配起來,變得更加直觀

    Trait Variations

    Device:在Device中,看到某個(gè)具體的機(jī)型,選擇設(shè)備,很容易被誤導(dǎo)以為特征變量會(huì)針對(duì)具體機(jī)型生效,其實(shí)并不是針對(duì)具體哪一個(gè)設(shè)備,而是相同sizeclass的一類設(shè)備,所以添加特征變量是影響一類設(shè)備

    Interface Style:亮色或暗色的界面風(fēng)格

    orientation:設(shè)備方向

    Vary for Traits :點(diǎn)擊后會(huì)彈出選擇Width、Height復(fù)選框,選擇寬度、高度或兩者,背景會(huì)變成藍(lán)色,左邊顯示的設(shè)備也會(huì)變化,選擇設(shè)備后,點(diǎn)擊Done Varying按鈕

    通過選中width復(fù)選框,將顯示varying 64 compact width devices
    通過選中height復(fù)選框,將顯示varying 98 compact height devices
    通過選中兩個(gè)復(fù)選框,將顯示varying 56 compact width regular height devices

    示例:

    設(shè)備選擇iPhone8,亮色風(fēng)格,豎屏(布局:wC hR)復(fù)選框選擇height,會(huì)發(fā)現(xiàn)豎屏是可以的,橫屏中view不見了,因?yàn)閕Phone8的橫屏布局是(wC hC),所以添加約束不會(huì)生效,要想適配的話,需要在布局是(wC hC)條件下,重新添加約束

一般組合有4種結(jié)果(wC hC)、(wR hR)、(wC hR)、(wR hC) (w是width h是height,C是Compact R是Regular)
-(wC hR):它適用于一切尺寸的豎屏iPhone
-(wR hR):適用所有橫屏、豎屏iPad
-(wC hC):適用于iPhone的橫屏上(除了iPhone11、iPhone Plus等)
-(wR hC):適用于iPhone 11 、iPhone Plus的橫屏等

示例:
如果使用iPhone8 (wC hR)UI布局,且分類按鈕選了Width,那么如果對(duì)iPhone8的UI進(jìn)行修改,會(huì)使同為wC的設(shè)備比如(wC hC)、(wC hR)的UI產(chǎn)生改變
如果使用iPhone8 (wC hR)UI布局,且分類按鈕選了Height,那么如果對(duì)iPhone8的UI進(jìn)行修改,會(huì)使同為hR的設(shè)備比如(wR hR)、(wC hR)的UI產(chǎn)生改變
如果使用iPhone8 (wC hR)UI布局,且分類按鈕選了Width和Height,那么如果對(duì)iPhone8的UI進(jìn)行修改,會(huì)使同為(wC hR)的設(shè)備的UI產(chǎn)生改變

根據(jù)不同布局,不同分類選項(xiàng),對(duì)相應(yīng)的布局產(chǎn)生影響,總結(jié)如下:

UI布局 Width Height Width & Height
CR CR、CC CR、RR CR
RC RC、RR RC、CC RC
CC CC、CR CC、RC CC
RR RR、RC RR、CR RR

在不同布局下,同一控件通過設(shè)置不同常數(shù)值實(shí)現(xiàn)相同效果,可以在配置在添加布局,而不是添加兩個(gè)約束

在配置在添加布局,而不是添加兩個(gè)約束

在不同設(shè)備上修改控件屬性,比如在iPhone豎屏上字體比較小,在iPhone橫屏上字體比較大,這時(shí)候使用Vary for Traits就沒有效果了,我們只需要為控件屬性增加布局,如果不需要點(diǎn)叉刪除

控件屬性增加布局

如果想指定尺寸選擇一個(gè)新控件,可以在控件屬性最下端,操作是類似,左邊的加號(hào)指定尺寸,Installed表示通用

控件大量屬性修改可通過installed添加布局

  • 修改約束

    方式一:
    需要選中將要編輯的約束(上圖小標(biāo)1),選中后約束在視圖中顯示為高亮(上圖小標(biāo)2),右邊會(huì)顯示修改約束的設(shè)置(上圖小標(biāo)3)

    First Item:第一個(gè)要設(shè)置的控件約束
    Second Item:第二個(gè)要參照的控件約束

    Relation:第一個(gè)控件與第二個(gè)控件約束值之間的關(guān)系
    -Less Than or Equal:小于等于
    -Equal:等于
    -Greater Than or Equal:大于等于

    Constraint:約束的偏移量

    Priority:約束的優(yōu)先級(jí)
    -Required(1000):默認(rèn)優(yōu)先級(jí)(高優(yōu)先級(jí))
    -Required(1000):中優(yōu)先級(jí)
    -Required(1000):低優(yōu)先級(jí)

    Multiplier:約束值放大倍數(shù)
    -Reverse Multiplier:反轉(zhuǎn)倍數(shù)(即 0.5 變?yōu)?2,4:3 變?yōu)?3:4)
    -Convert to Decimal:轉(zhuǎn)換為十進(jìn)制
    -Presets:預(yù)設(shè)值(也可以不使用預(yù)設(shè)值,自己設(shè)置需要的倍數(shù),如 0.5)
    -1:1 倍
    -4:3:4:3 倍
    -16:9:16:9 倍

    Placeholder(Remove at build time):編譯時(shí)移除該約束

    核心公式:第一個(gè)Item的屬性 =(<=/>=)第二個(gè)Item的屬性*Multiplier+Constant

    方式二:


    選中控件,選擇要修改的約束點(diǎn)擊Edit
  • 預(yù)覽(通過PreView可看到各設(shè)備預(yù)覽)

    如果xib完成一個(gè)效果,點(diǎn)擊PreView可以查看給個(gè)型號(hào)設(shè)備的效果.gif

代碼中設(shè)置AutoLayout

  • 利用 NSLayoutConstraint 類創(chuàng)建具體的約束對(duì)象
  • 添加、刪除約束對(duì)象到相應(yīng)的view上
    - (void)addConstraint:(NSLayoutConstraint *)constraint
    - (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints
    - (void)removeConstraint:(NSLayoutConstraint *)constraint 
    - (void)removeConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints
    

注意:
1.先禁止 autoresizing 功能,設(shè)置要添加約束的控件的下面屬性為 NO

testView.translatesAutoresizingMaskIntoConstraints = NO;

2.添加約束之前,一定要保證相關(guān)控件都已經(jīng)在各自的父控件上

[self.view addSubview:testView];

3.不用再給 view 設(shè)置 frame

  • 示例:


    redView(10,10,300,100)

    代碼實(shí)現(xiàn):

      [self.view setBackgroundColor:[UIColor whiteColor]];
      UIView *redView = [[UIView alloc]init];
      redView.backgroundColor = [UIColor redColor];
      [self.view addSubview:redView];
      //先禁止 autoresizing 功能,設(shè)置要添加約束的控件的下面屬性為 NO
      redView.translatesAutoresizingMaskIntoConstraints = NO;
      
     
      /*
       + (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c
       view1:要約束的控件
       attr1:要約束的類型(上、下、左、右等等)
       relation:與參照控件關(guān)系(小于等于、等于、大于等于)
       view2:參照控件
       attr2:要約束的類型(上、下、左、右等等)
       multiplier:約束值放大倍數(shù)
       c:偏移量
       */
    
      //redView(10,10,300,100)
      NSLayoutConstraint *xConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:10];
      [self.view addConstraint:xConstraint];
      
      NSLayoutConstraint *yConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:10];
      [self.view addConstraint:yConstraint];
    
      NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:300];
      [redView addConstraint:widthConstraint];
    
      NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:100];
      [redView addConstraint:heightConstraint];
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容