Introduction to Auto Layout

https://github.com/bluhar/IOSCook/tree/master/note15

Introduction to Auto Layout

利用自動布局,使得應(yīng)用既能在iPhone上運(yùn)行铁坎,也能在iPad上很好的顯示。應(yīng)用默認(rèn)是可以在iPad上運(yùn)行的愉老,只是屏幕周邊會顯示黑邊。

一個應(yīng)用既能在iPhone上運(yùn)行剖效,又能在iPad上運(yùn)行得就像為iPad開發(fā)的似的嫉入,叫做universal application.

修改項目target的General tab,修改Devices-->Universal.


此時在iPad上運(yùn)行應(yīng)用贱鄙,table view已經(jīng)可以撐滿屏幕劝贸,但是自定義的view姨谷,顯示得很不好逗宁。


Auto Layout

第四章講過,view's frame指定了他的大小和相對于superview的位置梦湘。目前定義視圖frame的方式是絕對坐標(biāo)瞎颗。

使用自動布局,可以以相對的方式描述視圖的布局捌议,從而在運(yùn)行時根據(jù)設(shè)備的屏幕大小確定frame哼拔。

蘋果設(shè)備的屏幕大小(points)如下表,points用來布局界面瓣颅,最終映射到屏幕的像素倦逐。retina 屏幕設(shè)備和非retina設(shè)備有相同的points,但是retina屏幕像素是非retina屏幕的兩倍宫补。

Device Width * Height (points)
iPhone/iPod(4S and earlier) 320 * 480
iPhone/iPod(5, 5C, 5S, 5g) 320 * 568
iPhone6 375 * 667
iPhone6 Plus 414 * 736
All iPads 768 * 1024

參考

Alignment rectangle


Alignment rectangle由一系列l(wèi)ayout attributes定義:

Layout attributes Description
Width/Height 定義alignment rectangle的大小
Top/Bottom/Left/Right 定義到alignment rectangle的邊距離其他view的alignment rectangle的距離檬姥,類似CSS中的margin
CenterX/CenterY 定義alignment rectangle的中心點
Baseline This value is the same as the bottom attribute for most, but not all, views. For example, UITextField defines its baseline to be the bottom of the text it displays rather than the bottom of the alignment rectangle. This keeps “descenders” (letters like ‘g’ and ‘p’ that descend below the baseline) from being obscured by a view right below the text field.
Leading/Trailing 這兩個值用在文本類的視圖曾我,如UITextField,UILabel健民。如果語言閱讀方向是從左向右抒巢,則leading同left,trailing同right;反之秉犹,leading同right蛉谜,trailing同left。

默認(rèn)崇堵,XIB中的每個view都有一個alignment rectangle型诚,并且都使用自動布局,但是默認(rèn)并不是你想要的效果鸳劳,你需要定義一些約束俺驶,系統(tǒng)根據(jù)這些約束來定義layout attributes,從而影響alignment rectangle棍辕。

Constraints

為BKDetailViewController的view的toolbar添加constraints暮现,使得其在iPad上可以友好顯示。

toolbar的顯示規(guī)則:

  • 應(yīng)該顯示屏幕的最下方
  • 應(yīng)該和屏幕寬度一樣
  • toolbar高度應(yīng)該是44 points (toolbar的蘋果標(biāo)準(zhǔn))

為將這些顯示規(guī)則在Interface Builder中轉(zhuǎn)變成constraints楚昭,要先理解視圖的nearest neighbor栖袋,nearest neighbor是在指定方向上最靠近視圖的同級視圖,如果在指定方向上沒有同級視圖抚太,則nearest neighbor是其superview(container)塘幅。

現(xiàn)在toolbar的constraints可描述為:

  1. toolbar的bottom距其nearest neighbor為0 points
  2. toolbar的left距其nearest neighbor為0 points
  3. toolbar的right距其nearest neighbor為0 points
  4. toolbar的height應(yīng)該是44 points

第二和第三條約束,其實就間接定義了toolbar的width為屏幕的寬度尿贫。第一和第四條約束电媳,間接定義了toolbar的top。

要添加這些約束庆亡,可以通過Interface Builder或代碼的方式匾乓。
蘋果推薦只要可能就使用Interface Builder的方式來添加,如果視圖是通過代碼的方式創(chuàng)建的又谋,可以通過代碼方式來添加約束拼缝,16章會講到。

Adding Constraints in Interface Builder

打開XIB文件彰亥,在右下角咧七,會發(fā)現(xiàn)Auto Layout Constraint Menu。


為toolbar添加left, right, bottom, height約束:


Adding more constraints

為name label添加約束任斋,使其固定在當(dāng)前位置继阻,并保持當(dāng)前的高和寬,選擇name label,點擊auto layout constraint menu的第二個Pin menu瘟檩,激活這些約束犬第。

現(xiàn)在為name label的text field添加約束,激活當(dāng)前的left和right芒帕。這樣即使屏幕變寬了歉嗓,其寬度會自動擴(kuò)展,保持右側(cè)距nearest neighbor為right指定的值背蟆。


但是只設(shè)置left和right鉴分,發(fā)現(xiàn)提示異常:



這是因為沒有指定Y軸方向的約束,你可以打開Pin menu带膀,為name text field激活top屬性志珍。但是還有更好的方法:根據(jù)name label來定位name text field,將name text field和name label的Baseline對齊垛叨。

選擇text field伦糯,按下Shift鍵,然后選擇name label嗽元,點擊auto layout constraint menu的第一個menu: Align敛纲,然后選中Baselines,并添加這個約束剂癌。

Adding even more constraints

現(xiàn)在已經(jīng)知道如何通過Pin和Align menu來添加約束淤翔,還可以通過Control-drag來添加約束。
Control-drag一個view到另一個view佩谷,然后釋放鼠標(biāo)旁壮,獲得一個可以添加的約束列表。約束是動態(tài)生成的谐檀,根據(jù)drag的方向以及兩個veiw抡谐。

現(xiàn)在為Serial label添加top, left, with, height約束。
top:保持當(dāng)前距name label的距離桐猬,
left:和name label左對齊
with/height:保持當(dāng)前的值


上面的gif麦撵,首先為serial label激活了top屬性,保持當(dāng)前top距name label(top方向的nearest neighbor)的距離课幕。其次厦坛,選擇了left屬性五垮,相當(dāng)于點擊Align menu乍惊,選中Leading Edges。最后放仗,Control-drag自己到自己润绎,并且拖動方向?qū)蔷€,這樣width和height才會同時出現(xiàn),按下Shift鍵可以同時選中with/height莉撇,然后按下回車鍵呢蛤。

下面為serial text field添加leading(left),baseline(和serial label baseline對齊)棍郎,trailing(right)約束其障。


總結(jié):對于要和其他view對齊的constraint,用Control-drag的方式更方便涂佃,對于其他約束励翼,比如width, height,用Pin menu更方便辜荠。

Priority

每個約束都有一個priority屬性汽抚,當(dāng)有多個約束沖突時,通過此值來決定優(yōu)先級伯病。
值是1-1000造烁,1000代表為必須約束,默認(rèn)情況下每個約束都是必須約束午笛。所以當(dāng)多個約束有相同的priority值惭蟋,就無法解決約束沖突的問題。

當(dāng)約束沖突時药磺,可以刪除某約束或減小某約束的priority來解決沖突敞葛。

調(diào)試約束

當(dāng)添加很多約束后,可能會造成:約束沖突与涡,缺少約束惹谐,約束與視圖不匹配等問題,需要通過調(diào)試來解決這些問題驼卖。

Ambiguous layout

不確定的布局氨肌,現(xiàn)在添加兩個label并將其背景色改為灰色,來模擬abmiguous layout酌畜。

在BKDetailViewController.m中重寫viewDidLayoutSubviews方法怎囚,檢查其子視圖是否有不確定的布局。

- (void)viewDidLayoutSubviews{
    // 檢查子視圖是否有ambiguous layout
    for (UIView *subview in self.view.subviews) {
        if ([subview hasAmbiguousLayout]) {
            NSLog(@"AMBIGUOUS: %@", subview);
        }
    }
}

當(dāng)視圖大小發(fā)生變化(比如屏幕旋轉(zhuǎn))或是視圖第一次被顯示時桥胞,會調(diào)用viewDidLayoutSubviews方法恳守。

在backgroundTapped方法中調(diào)用exerciseAmbiguityInLayout,此時運(yùn)行應(yīng)用贩虾,點擊detail視圖的背景催烘,可以看到兩個label的寬度來回切換。

- (IBAction)backgroundTapped:(id)sender {
    // 隱藏鍵盤
    [self.view endEditing:YES];
   
    for (UIView *subview in self.view.subviews) {
        if ([subview hasAmbiguousLayout]) {
            [subview exerciseAmbiguityInLayout];
        }
    }
}

由于兩個label的寬度沒有明確的約束缎罢,所以造成了這兩種情況都滿足目前的約束伊群,只要為一個label添加width約束考杉,就可以解決此問題。Control-drag一個label到另外一個舰始,選擇equal width崇棠,讓兩個label保持相同的width。

exerciseAmbiguityInLayout方法是用來調(diào)試的丸卷,當(dāng)要發(fā)布應(yīng)用時枕稀,要刪除這種調(diào)試方法。

Unsatisfiable constraints

當(dāng)約束沖突時谜嫉,產(chǎn)生unsatisfiable constraint抽莱。
比如為一個label添加了leading, trailing約束,然后又添加了width約束骄恶,這就造成了約束沖突食铐,因為leading, trailing已經(jīng)可以確定其寬度了,不需要再添加width約束僧鲁。

當(dāng)有約束沖突時虐呻,console中會有以下信息,刪除不必須的約束即可解決:

2015-08-10 00:45:47.957 Homepwner[1500:70b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x8d82d10 H:[UILabel:0x8d82c00(149)]>",
    "<NSLayoutConstraint:0x8d8a650 H:[UILabel:0x8d82c00]-(85)-|   (Names: '|':UIControl:0x8d82080 )>",
    "<NSLayoutConstraint:0x8d8a680 H:|-(86)-[UILabel:0x8d82c00]   (Names: '|':UIControl:0x8d82080 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x8d9ffa0 h=-&- v=-&- UIControl:0x8d82080.width == _UIParallaxDimmingView:0x8d8ed10.width>",
    "<NSAutoresizingMaskLayoutConstraint:0x8da0740 h=--& v=--& H:[_UIParallaxDimmingView:0x8d8ed10(768)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x8d82d10 H:[UILabel:0x8d82c00(149)]>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Misplaced views

當(dāng)XIB文件中寞秃,view的frame當(dāng)前的位置和約束定義的位置(比如top, left等)不匹配時斟叼,就會有misplace view problem。

要解決此問題有兩種方式春寿,要么更新視圖位置匹配約束的定義朗涩,要么更新約束匹配視圖的位置。

打開auto layout constraint menu的第三個menu绑改,即Resolve Auto Layout Issues menu谢床。選擇Update frames或Update constraints。


Debugging Using the Auto Layout Trace

UIWindow有一個私有的實例方法_autolayoutTrace厘线,該方法會返回window的完整視圖結(jié)構(gòu)识腿,如果視圖有ambiguous layout,會被添加tag: AMBIGUOUS LAYOUT.

代碼中添加一個斷點造壮,斷點位置要保證view已經(jīng)顯示在屏幕上渡讼,在斷點處運(yùn)行以下代碼查看:

(lldb) po [[UIWindow keyWindow] _autolayoutTrace]

Multiple XIB files

為XIB文件添加后綴,來達(dá)到在不同的設(shè)備上view controller加載不同的XIB文件耳璧。即使如此成箫,還是要為XIB文件使用auto layout,auto layout可以響應(yīng)用戶語言旨枯,字體蹬昌,設(shè)備方向的變化。

  • BKDetailViewController~iphone.xib
  • BKDetailViewController~ipad.xib

本文是對《iOS Programming The Big Nerd Ranch Guide 4th Edition》第十五章的總結(jié)召廷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凳厢,一起剝皮案震驚了整個濱河市账胧,隨后出現(xiàn)的幾起案子竞慢,更是在濱河造成了極大的恐慌先紫,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筹煮,死亡現(xiàn)場離奇詭異遮精,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)败潦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門本冲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人劫扒,你說我怎么就攤上這事檬洞。” “怎么了沟饥?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵添怔,是天一觀的道長。 經(jīng)常有香客問我贤旷,道長广料,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任幼驶,我火速辦了婚禮艾杏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盅藻。我一直安慰自己购桑,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布氏淑。 她就那樣靜靜地躺著其兴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夸政。 梳的紋絲不亂的頭發(fā)上元旬,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機(jī)與錄音守问,去河邊找鬼匀归。 笑死,一個胖子當(dāng)著我的面吹牛耗帕,可吹牛的內(nèi)容都是我干的穆端。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼仿便,長吁一口氣:“原來是場噩夢啊……” “哼体啰!你這毒婦竟也來了攒巍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤荒勇,失蹤者是張志新(化名)和其女友劉穎柒莉,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沽翔,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡兢孝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了仅偎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跨蟹。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖橘沥,靈堂內(nèi)的尸體忽然破棺而出窗轩,到底是詐尸還是另有隱情,我是刑警寧澤座咆,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布痢艺,位于F島的核電站,受9級特大地震影響箫措,放射性物質(zhì)發(fā)生泄漏腹备。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一斤蔓、第九天 我趴在偏房一處隱蔽的房頂上張望植酥。 院中可真熱鬧,春花似錦弦牡、人聲如沸友驮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卸留。三九已至,卻和暖如春椭豫,著一層夾襖步出監(jiān)牢的瞬間耻瑟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工赏酥, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留喳整,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓裸扶,卻偏偏與公主長得像框都,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子呵晨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

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