iOS頁面的布局方式

iOS有三種基本的界面布局的方法,分別是手寫UI,xib和storyboard。手寫UI是最早進(jìn)行UI界面布局的方法案铺,優(yōu)點是靈活自由,缺點是需要寫大段的代碼進(jìn)行布局梆靖。xib也是比較早出現(xiàn)的UI布局的方式控汉,優(yōu)點是不需要手寫代碼,但是每個界面對應(yīng)一個xib返吻,管理起來復(fù)雜姑子。而storyboard則是在iOS5以后出現(xiàn)的,是蘋果官方主推的一個代替xib的策略测僵,不僅能將xib匯總統(tǒng)一管理壁酬,還可以描述各種場景之間的過渡,缺點是多人協(xié)作開發(fā)時容易產(chǎn)生沖突恨课。

下面主要介紹的是手寫頁面布局舆乔。

一、AutoresizingMasks

可以使用 AutoresizingMasks 進(jìn)行頁面布局剂公,在 UIView 中有一個autoresizingMask的屬性希俩,它對應(yīng)的是一個枚舉的值,屬性的意思就是自動調(diào)整子控件與父控件中間的位置纲辽,寬高颜武。默認(rèn)值是UIViewAutoresizingNone,控件不會隨父視圖的改變而改變拖吼。

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
     UIViewAutoresizingNone = 0,
     UIViewAutoresizingFlexibleLeftMargin = 1 << 0, // 自動調(diào)整view與父視圖左邊距鳞上,以保證右邊距不變
     UIViewAutoresizingFlexibleWidth = 1 << 1, // 自動調(diào)整view的寬度,保證左邊距和右邊距不變
     UIViewAutoresizingFlexibleRightMargin = 1 << 2, // 自動調(diào)整view與父視圖右邊距吊档,以保證左邊距不變
     UIViewAutoresizingFlexibleTopMargin = 1 << 3, // 自動調(diào)整view與父視圖上邊距篙议,以保證下邊距不變
     UIViewAutoresizingFlexibleHeight = 1 << 4, // 自動調(diào)整view的高度,以保證上邊距和下邊距不變
     UIViewAutoresizingFlexibleBottomMargin = 1 << 5 // 自動調(diào)整view與父視圖的下邊距,以保證上邊距不變
}

AutoresizingMasks是對未來變化的一種預(yù)期鬼贱,系統(tǒng)會生成frame的布局,當(dāng)遇到需要使用到多個值的場景時移怯,支持使用|操作符。
例如这难,需要設(shè)置播放器浮層隨播放器大小變化:

UIView *overlay = [[UIView alloc] init];
overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:overlay];

Autoresizing需要注意的是舟误,storyboard中設(shè)置的約束和手寫代碼中設(shè)置的約束是相反的。storyboard 圖形頁面里點的右邊的線和下邊的線的意思是“固定”姻乓。

二嵌溢、Frame

frame指的是當(dāng)前視圖在其父視圖中的位置和大小。
在初始化 view 的時候蹋岩,可以設(shè)置 view 的frame

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(10, 20, 30, 40)]; 

初始化一個距離父視圖左邊距10堵腹,上邊距20,寬30星澳,高40的視圖。也可以修改聲明View的位置以及大小旱易。

view.frame = CGRectMake(20, 10, 40, 30);

設(shè)置和修改視圖的 frame 可以完成對界面的布局禁偎。

2.1 bounds

提到 frame 不得不提 bounds,bounds指的是前視圖在其自身坐標(biāo)系統(tǒng)中的位置和大小阀坏∪缗可以看到兩者的區(qū)別在于坐標(biāo)系不同。

2.2 layoutSubviews

需要重新布局視圖可以使用 layoutSubviews

1)可以在view里重寫layoutSubviews

2)可以在view controller里使用

viewWillLayoutSubviews 在autoresizingMasks前調(diào)用

viewDidLayoutSubviews 在autoresizingMasks后調(diào)用忌堂,肯定會覆蓋autoresizingMasks的結(jié)果

layoutSubviews可能會在不需要調(diào)用的時候調(diào)用盒至,如果layoutSubviews的比較復(fù)雜,可能會卡頓

三士修、自動布局AutoLayout

前面講到的 frame 主要用于視圖的絕對位置枷遂,但是 iOS 設(shè)備有多個尺寸,如何對不同尺寸進(jìn)行適應(yīng)棋嘲,蘋果的解決方案是使用 AutoLayout酒唉。

如果是從代碼層面開始使用 Autolayout,需要對使用的 View 的translatesAutoresizingMaskIntoConstraints 的屬性設(shè)置為NO沸移。即可開始通過代碼添加Constraint痪伦,否則View還是會按照以往的autoresizingMask進(jìn)行計算。而在 Interface Builder 中勾選了Use Auto layout雹锣,translatesAutoresizingMaskIntoConstraints 屬性都會被默認(rèn)設(shè)置NO网沾。

3.1 約束

自動布局里最重要的組成部分就是約束。分別可以設(shè)置視圖相對于另一個視圖的 leading蕊爵、trailing辉哥、top、bottom攒射、CenterX证薇、CenterY 等關(guān)系度苔。根據(jù)這些約束來確定視圖的相對位置。

視圖的約束之間的關(guān)系為線型關(guān)系浑度。例如寇窑,視圖Y 相對于 視圖X 的位置可以表示為一個線性變換,即

Y = kX + b

即 Y 是 X 某個方向坐標(biāo)或大小的 k 倍并偏移 b箩张。k 和 b 的大小可以是0甩骏。如果 k = 1, b = 0先慷, 則表示 Y 和 X 分別表示視圖的寬饮笛,則等式表示 Y 和 X 的寬度相等。

AutoLayout 的核心是:Every view requires at least two constraints along each axis to set position and size. 即在每個坐標(biāo)軸上至少需要2個約束來確定視圖位置论熙。

3.2 Ambiguous Layout

在開發(fā)過程中福青,你可以通過調(diào)用hasAmbiguousLayout 來測試你的view約束是否足夠的。函數(shù)會返回布爾值脓诡。如果有一個不同的frame就會返回yes无午,如果view的約束完全指定了就會返回no。
一個設(shè)定了完全約束的view的子view也可能存在ambiguous layout祝谚,需要為每一個view單獨測試layout是否存在ambiguous layout宪迟。

3.3 Intrinsic Content Size

使用autolayout時,view的content扮演著非常重要的角色交惯。每個view的intrinsicContentSize描述了不會剪切的顯示完整view content的最小空間次泽。例如一個image view,content size根據(jù)image顯示的size設(shè)置席爽。一個大的image需要一個大的固有的content size意荤。image的大小提供給了view。
對于button只锻,固有的content size根據(jù)他的title而有不同袭异。隨著title增長或者縮短,button的固有的content size也會調(diào)節(jié)來做適應(yīng)炬藤,可以根據(jù)你自定義的font size和title text而有變化御铃。

3.4 Compression Resistance and Content Hugging

3.4.1 compression resistance

壓縮阻力表示一個視圖的抗壓縮性。一個有高compression resistance的視圖會防止被壓縮沈矿。也不會允許content被裁剪上真,而會嘗試保存他的最小固有content size。
autolayout經(jīng)常遇到兩個沖突的請求羹膳。當(dāng)只有一個請求會成功時睡互,他就會滿足高優(yōu)先級的那個。可以分別設(shè)置水平和垂直方向的Compression Resistance就珠。value從1(最低)到1,000(請求的優(yōu)先級)不等寇壳。默認(rèn)的是750。

[button setContentCompressionResistancePriority:500 forAxis:UILayoutConstraintAxisHorizontal]; 

3.4.2 content hugging

抗拉屬性表示view防止被拉伸的屬性妻怎,和壓縮阻力類似壳炎。默認(rèn)值為250。

[button setContentHuggingPriority:501 forAxis:UILayoutConstraintAxisHorizontal];

3.5 VFL

Visual Format Language逼侦,即“可視化格式語言”匿辩。直接手寫約束很復(fù)雜,使用VFL相對簡單很多榛丢,但比較難進(jìn)行調(diào)試铲球。

  [self.view addConstraints: [NSLayoutConstraint            
constraintsWithVisualFormat:@"V:[view1]-8-[view2]"             
                    options:NSLayoutFormatAlignAllLeading
                    metrics:nil
                      views:NSDictionaryOfVariableBindings(view1, view2)]];

3.6 Masonry

VFL的寫法也相當(dāng)復(fù)雜,可以使用第三方框架 Masonry晰赞,Masonry 是一個輕量級的布局框架稼病,Masonry 源碼:https://github.com/Masonry/Masonry

例如,設(shè)置view1相對父View的每個邊距離為padding:

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(padding);
}];

需要注意的是掖鱼,在結(jié)構(gòu)一樣的情況下用mas_updateConstraints然走,會更新當(dāng)前的約束,但是如果要覆蓋緣由約束重新添加锨用,則需要使用方法用mas_remakeConstraints

constraint加到兩個view的公共父view上,因此有一個奇怪的現(xiàn)象是一個view不持有自己的約束隘谣,而被其他view持有增拥。在 Masonry 中,實際添加constraint的不一定是約束的持有者

四寻歧、更新布局方法

設(shè)置好約束以后掌栅,布局是如何更新的呢?

Constraints

- (void)updateConstraintsIfNeeded    // 立即重新計算約束码泛,如果在這之前addConstraints猾封,就可以更新約束
- (void)setNeedsUpdateConstraints   // 立即返回,標(biāo)記說需要改變約束值噪珊,在當(dāng)前update cycle結(jié)束后更新之前所有標(biāo)記過要改變的約束晌缘,調(diào)用updateConstraints方法

Layout

- (void)layoutIfNeeded     // 立即更新布局,重新計算約束痢站,如果在這之前addConstraints就會立即反應(yīng)在頁面上
- (void)setNeedsLayout    // 同Constraints磷箕,不過是更新布局
- (void)layoutSubviews    // 布局當(dāng)前頁面的子頁面

Draw

- (void)setNeedsDisplay   // 同Constraints,不過是重新渲染

4.1 Constraints,Layout阵难,Draw調(diào)用順序

一個頁面更新的順序一般為
調(diào)用約束計算出frame(Constraints)→ 根據(jù)計算出的frame重新布局(Layout) → 根據(jù)重新布局的結(jié)果進(jìn)行圖像渲染(Draw)

layout的改變會導(dǎo)致重新計算Constraints
layoutIfNeeded會調(diào)用updateConstraintsIfNeeded

Constraints的計算順序是低到上 (從subview到superview)
layout的更新順序是從頂?shù)较拢◤膕uperview到subview)

4.2 frame和約束區(qū)別

1岳枷、frame是不可以累加的,只能被替換掉,但是constraint可以累加

2空繁、frame不可以跨級添加殿衰,但是contraint可以跨層級

3、contraint可以設(shè)定priority

另外盛泡,需要注意的是闷祥,在autolayout下使用frame,會把frame轉(zhuǎn)化成autolayout的約束饭于,如果再進(jìn)行約束的設(shè)置蜀踏,由于多次累加可能會造成沖突

github博客:https://wf96390.github.io/blog/2016/03/16/autolayout/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掰吕,隨后出現(xiàn)的幾起案子果覆,更是在濱河造成了極大的恐慌,老刑警劉巖殖熟,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件局待,死亡現(xiàn)場離奇詭異,居然都是意外死亡菱属,警方通過查閱死者的電腦和手機(jī)钳榨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纽门,“玉大人薛耻,你說我怎么就攤上這事∩土辏” “怎么了饼齿?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝙搔。 經(jīng)常有香客問我缕溉,道長,這世上最難降的妖魔是什么吃型? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任证鸥,我火速辦了婚禮,結(jié)果婚禮上勤晚,老公的妹妹穿的比我還像新娘枉层。我一直安慰自己,他們只是感情好赐写,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布返干。 她就那樣靜靜地躺著,像睡著了一般血淌。 火紅的嫁衣襯著肌膚如雪矩欠。 梳的紋絲不亂的頭發(fā)上财剖,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音癌淮,去河邊找鬼躺坟。 笑死,一個胖子當(dāng)著我的面吹牛乳蓄,可吹牛的內(nèi)容都是我干的咪橙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼虚倒,長吁一口氣:“原來是場噩夢啊……” “哼美侦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起魂奥,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤菠剩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后耻煤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體具壮,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年哈蝇,在試婚紗的時候發(fā)現(xiàn)自己被綠了棺妓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡炮赦,死狀恐怖怜跑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吠勘,我是刑警寧澤性芬,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站看幼,受9級特大地震影響批旺,放射性物質(zhì)發(fā)生泄漏幌陕。R本人自食惡果不足惜诵姜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搏熄。 院中可真熱鬧棚唆,春花似錦、人聲如沸心例。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽止后。三九已至瞎惫,卻和暖如春溜腐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓜喇。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工挺益, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乘寒。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓望众,卻偏偏與公主長得像,于是被迫代替她去往敵國和親伞辛。 傳聞我的和親對象是個殘疾皇子烂翰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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