Autolayout

一、簡介

  1. 在以前的iOS程序中,經常編寫大量的坐標計算代碼,為了保證在3.5 inch和4.0 inch屏幕上都能有完美的UI界面效果,有時還需要分別為2種屏幕編寫不同的坐標計算代碼,即傳說中的“屏幕適配”。

  2. 那什么是Autolayout呢?
    Autolayout是一種“自動布局”技術,專門用來布局UI界面的。Autolayout自iOS6開始引入,由于Xcode4的不給力,當時并沒有得到很大推廣。自iOS7(Xcode5)開始,Autolayout的開發效率得到很大的提升。蘋果官方也推薦開發者盡量使Autolayout來布局UI界面,它能很輕松地解決屏幕適配的問題。

  3. 在Autolayout之前,有Autoresizing可以作屏幕適配,但局限性較大,有些任務根本無法完成,相比之下,Autolayout的功能比Autoresizing強大很多。

  4. 如何使用呢?
    Autolayout有2個核心概念:參照和約束。它通過內定的Constraint(約束)和各項條件來計算出合理的布局.而這個合理的布局,符合我們的的預期和意圖。將我們想象中的結果展現出來。Constraint的設定非常靈活,實現一種布局的方法可以通過多Constraint來完成.
    以下幾點是我們在開始使用之前必須弄清楚的事情:

  • 我們要拋棄以往舊的布局方式不再去關注ViewFrame,center,和autoresizing,因為這些坐標和大小的定位都可以通過來Auto Layout完成。
  • 理解每一種Constraint的含義,否則,當你去看別人的實現的Constraint時,就會有種看天書的感覺。
  • 按意圖設計,一切按我們理想中的效果去布局,只要約束設定的合理,就一定能夠完成目標布局。

二、用xib或者storyboard來實現Autolayout

  1. 先從Interface Builder開始吧. 打開某個xib或者storyboard,
    在右側Show in file inspector里面找到Ues Autolayout,將其勾選。如下圖:


    自此,Autolayout便啟用成功,autoresizingMask被廢棄.其所有以往的功能和特性都被Autolayout取代.
    注意:
    現在我們定位控件位置的方式,不再像以前一樣,計算好每一個控件具體的位置,x是多少,y是多少。而是思考,這個控件離左邊是相隔多少距離,或者離頂部或底部相隔多少距離。
    而有些規則性的事情還是類似的,比如我們定位一個控制的位置,一定要有x,y兩個坐標點同時有值,少一個都不能正常顯示。
    同樣Autolayout在創建約束時也一樣,在思考完離頂部距離以后,還需要思考離頂部距離,否則控件的顯示位置一樣無法正常顯示.
    換言之,要讓Autolayout計算出合理的位置,需要保證水平距離和垂直距離同時存在. 否則IDE,都會給出警告,提示這樣的布局Ambiguous Layout(模凌兩可)

  2. Interface Builder提供Autolayout的功能:

2.1如下圖:



詳解:
(選擇兩個view時可設置)
Leading Edges:左邊對齊
Trailing Edges:右邊對齊
Top Edges:頂部對齊
Bottom Edges:底部對齊
Horizontal Centers:水平居中
Vertical Centers:垂直居中
Baselines:文本底標線對齊

(單選擇一個view時可設置)
Horizontal Center in Container:對于父view的水平居中
Vertical Center in Container:對于父view的垂直居中

2.2如下圖:



(選擇框)
None:添加完約束后不進行任何操作,
Items of New Constraints:在添加約束后重新擺放約束涉及到的view
All Frames in Container:在添加約束后重新擺放所有這個容器內的view

2.3如下圖:


詳解:
上面的十字是"與最近的鄰居的約束", 填上數字, 單擊虛線變成實線就是要添加這個約束.
這里的"鄰居"是將一個包含子view的父view看做一個裝了一堆積木的盒子, 積木相對于盒子的邊框和其他的積木都作為"鄰居"。

(定義的寬高數據約束)
Widths:寬度指定,
Height:高度指定,

(定義多個view之間的寬高約束)
Equal Widths:寬度相同,
Equal Heights:高度相同,

(定義多個view之間的寬高約束)
Align:多個view之間的對齊約束

2.4如下圖



詳解:
(上半部分菜單的操作對象是當前選中的view, 下半部分的操作對象是選中view內的view)
Update Frames:刷新frame(使用當前已經設置的所有約束),
Update Constraints:刷新約束(根據當前的約束和frame, 更新約束的constant值),
Add Missing Constraints:添加缺失的約束(自動添加系統認為你應該添加卻忘記添加的約束, 測試中經常搞出沖突)
Reset to Suggested Constraints:重置為系統建議的約束(清理系統認為重復/沖突的約束, 測試中經常搞出問題)
Clear Constraints:清理所有約束(刪除對象上綁定的所有約束)

三、代碼創建AutoLayout

代碼創建的約束有兩種方式:
1:常規約束,寫法非常冗長,但能實現所有的約束方式以及非常特殊的約束方式,代碼如下:

  // 添加兩個控件到父控件上添加藍色View
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
self.blueView = blueView;

  // 添加紅色View
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];

 // 禁用auturezing
blueView.translatesAutoresizingMaskIntoConstraints = NO;
 //注意, 這里設置父控件無效,要設置自己的translatesAutoresizingMaskIntoConstraints屬性為NO。
redView.translatesAutoresizingMaskIntoConstraints = NO;

 // 添加約束
 // 添加藍色VIew距離父控件左邊的距離固定為20  X
NSLayoutConstraint *leftCos = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:20];
[self.view addConstraint:leftCos];

 // 紅色的頂部和藍色的底部距離固定 Y
NSLayoutConstraint *redTopCos = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20];
[self.view addConstraint:redTopCos];

注意:

  • 如果是從代碼層面開始使用Autolayout,需要對使用的View的translatesAutoresizingMaskIntoConstraints的屬性設置為NO.

  • 添加約束之前一定要將子視圖優先addSubview到父視圖中,否則在添加約束時會產生編譯器警告.而我們在理解的時候,可以通過這種方式來理解.
    Item == first item 需要設置約束的控件
    attribute == 需要設置的約束
    relatedBy == relation 等于
    toItem == second item 被參照的控件
    attribute == 需要設置的約束
    multiplier == multiplier 乘以
    constant = constant 加上

2.可視化格式語言約束(VFL)
所謂可視化格式語言約束,是一種很直觀的理解方式,當然,前提是你已經熟練理解這套語言的規則.
VFL是蘋果公司為了簡化Autolayout的編碼而推出的抽象語言。
通過可視化語言可以一次性創建多個約束. 這對于第一次方式來說,是相當方面和容易理解的.但可視化語言不是所有約束都能滿足.
我們可以用正則表達式的學習方式來學習這項可視化格式語言.舉例代碼如下:


// 添加兩個控件到父控件上
// 添加藍色View
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];

// 添加紅色View
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];

// 禁用Autoresizing
blueView.translatesAutoresizingMaskIntoConstraints = NO;
redView.translatesAutoresizingMaskIntoConstraints = NO;

// 添加約束
// 設置藍色View距離左邊和右邊有20的的間距 X 和 寬度
NSArray *blueViewH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nil views:@{@"blueView" : blueView}];
[self.view addConstraints:blueViewH];

// 設置藍色View距離頂部有20的間距, 并且高度等于50 Y 和高度
// 設置紅色View距離藍色底部有20的間距, 并且紅色View的高度等于藍色View的高度 Y 和高度
// 并且設置紅色和藍色右對齊
NSArray *blueViewV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[blueView(50)]-20-[redView(==blueView)]" options:NSLayoutFormatAlignAllRight metrics:nil views:@{@"blueView" : blueView, @"redView": redView}];
[self.view addConstraints:blueViewV];
NSLayoutConstraint *redVeiwW = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0];
[self.view addConstraint:redVeiwW];

注意: 在VFL語句中, 是不支持乘除法

VFL實例:

  • H:[cancelButton(72)]-12-[acceptButton(50)]
    canelButton寬72,acceptButton寬50,它們之間間距12

  • H:[wideView(>=60@700)]
    wideView寬度大于等于60point,該約束條件優先級為700(優先級最大值為1000,優先級越高的約束越先被滿足)

  • V:[redBox][yellowBox(==redBox)]
    豎直方向上,先有一個redBox,其下方緊接一個高度等于redBox高度的yellowBox

  • H:|-10-[Find]-[FindNext]-[FindField(>=20)]-|
    水平方向上,Find距離父view左邊緣默認間隔寬度,之后是FindNext距離Find間隔默認寬度;再之后是寬度不小于20的FindField,它和FindNext以及父view右邊緣的間距都是默認寬度。(豎線“|” 表示superview的邊緣)

四、VFL的使用

使用VFL來創建約束數組
+ (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;

詳解:
lFormat: VFL語句
options: 對齊方式
metrics:VFL語句中用到的變量值
views:VFL語句中用到的控件
metrics:可以把VFL語句中的常量,抽取成為變量。由于是個字典,要包裝成對象類型

五、AutoLayout實現動畫

1.約束也可以在storyboard里面進行連線,只需要修改控件的約束,也能實現動畫。

[UIView animateWithDuration:1.0 animations:^{
   [添加了約束的view layoutIfNeeded];
}];

  1. 可以在UIView中讓多個約束一起執行動畫
    如果控件有默認的高度,只需要設置autoLayout的X值和Y值,autoLayout會自動計算出控件的寬高。

六、Autolayout的警告與錯誤

1.警告
控件的frame不匹配所添加的約束,比如約束控件的寬度為100,而控件現在的寬度是110.

2.錯誤
(1).缺乏必要的約束,只約束了寬度和高度,沒有約束具體的位置。
(2).兩個約束沖突,比如1個約束控件的寬度為100,一個約束控件的寬度為110

七、特殊情況

  1. UILabel
    UILabel不用約束寬度,會自動根據文字多少自動改變寬度——不用添加寬度約束(不會報錯)

  2. UISearchbar
    searchbar添加到navigationBar的titleView中時,會自動伸長到整個navigationBar,對其添加的任何約束和frame屬性都沒有用。
    解決方法:添加searchBar到另外一個普通的view中再設置為titleView

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容