iOS 我們不熟悉的自動布局(一).

昨天從<<iOS Auto Layout開發(fā)秘籍>>的書中看到了我們在實際開啊中不常用看到的VFL和系統(tǒng)的自動布局類.雖然我們的前輩們已經(jīng)開源了masonry等自動布局框架,但是他們還是在系統(tǒng)的框架基礎上進行的再次封裝.因為系統(tǒng)的自動布局約束看起來并不是那么簡約.代碼量比較多.但是我們在使用第三方約束的時候就應該明白,我們系統(tǒng)約束到底是什么樣的.今天就給大家?guī)硐到y(tǒng)的自動布局約束類.在此并不包括IB中的自動布局.

系統(tǒng)原生自動布局

1.系統(tǒng)原生的自動布局還有劃分,一種就是masonry封裝的

+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullableid)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c

如果你看過masonry的源碼肯定會看到這個方法.因為他最終都是通過這個方法對需要約束的視圖進行約束的.

還有一種就是我們今天分享的重點VFL.以前都只是聽說過系統(tǒng)有這種布局方式但是從來沒有用過.那么系統(tǒng)提供兩種布局方式到底有什么異同啦.

第一種約束方式.

先來敲一段和masonry使用同樣方式的約束吧.

首先我們定義一個視圖讓其距離left 64, right 64,top 64,bottom 64.

代碼
效果

由于開發(fā)都用masonry所以系統(tǒng)的方法很多都是記憶很模糊.那么我們首先來看看系統(tǒng)的這些方法.

添加or刪除約束

前兩個是添加約束的方法,后面兩個書刪除約束的方法.

這兩個方法很簡單,一個參數(shù)是NSLayoutConstraint,一個是數(shù)組,但數(shù)組元素還是NSLayoutConstraint.這個就不多解釋了.如果有人不知道NSLayoutConstraint,那么就說一下吧.

從字面意思就能看出來他到底是干什么的了.NS不多解釋蘋果老大哥的Foundation的標識例如NSArray.layout就是布局的意思.那后面這個是什么啦?然而這個就是我們的約束.

上面的方法是在UIView的分類中添加的,那結果就是只要你繼承或間接繼承都會有這個添加和刪除的方法.

關鍵字:update

從上面這張截圖中我們看到了每個方法中都有update這個關鍵字.那么我們的初步估計就是更新約束.或者是更新約束后更新視圖.蘋果的方法最大的特點是意思寫在明面上,這也就要求我們在定義我們的方法時一定要能從方法名看出作用.

1.updateConstraintsIfNeeded調(diào)用這個方法會立即更新約束.

2.系統(tǒng)實際用來更新約束的方法

3.這個方法的調(diào)用的返回值決定是否去掉用系統(tǒng)實際更新約束的方法.作為正常布局的一部分.

4.告訴layoutView需要更新約束循榆,在下次計算或者更新約束會更新約束

從上面的方法我們可以總結出以下幾點.當我們在未來的某個時刻需要更新約束時,會首先調(diào)用setNeedsUpdateConstraints.這個方法.然后在某個時刻上調(diào)用updateConstraintsIfNeeded這個方法.這個方法調(diào)用會調(diào)用updateConstraints這個方法來完成正常的更新約束.

如果只是淡淡的調(diào)用updateConstraintsIfNeeded這個方法,可能并不會調(diào)用updateConstraints這個方法來更新約束.因為吐過視圖上的約束可能還沒有發(fā)生變化且沒有標記需要更新.

系統(tǒng)在調(diào)用layoutSubviews時,就會調(diào)用updateContraintsIfNeeded,通過更新約束,用super view到subview的層次順序,來計算frame,返向確定布局.

stackoverFlow上有關于改變約束的方法研究.

1.如果想立即改變約束,調(diào)用setNeedsLayout

2.吐過想改變view的一些屬性如offsets可能會導致布局的改變,那么會調(diào)用setNeedsUpdateConstraints,更多的時候和面還需要加setNeedsLayout.

3.如果想立即改變布局,如會形成新的frame,那么需要在調(diào)用layoutIfNeeded.


系統(tǒng)中還有很多方法,就不一一介紹了.等到用到時在進行解釋.

上面的布局只是一個簡單的相對于self.view 的布局.那么兩個視圖應該怎樣布局啦.

布局布標,view1和view2并排放置,view2的left距離view的right 15px.并且view1和view2等高等寬,并且centerY等于self.view的centerY.

同一個父視圖布局兩個左右間距

好了如果左右間距都可以了,上下間距也是可以的.這個留在后面給大家當練習吧.

在這本書上還知道我們?nèi)绾涡薷挠衅缌x的約束和尋找因為不正確約束導致視圖丟失的方法.

1.規(guī)則不一致的約束.有這么一個經(jīng)典的例子就是viewA是viewB寬度的三倍,viewB是viewA寬度的2倍.請用代碼實現(xiàn).

當然代碼我相信大家都能寫的出來.但是肯定會有人問這個約束規(guī)則能實現(xiàn)嗎?

答案是肯定的:絕對能實現(xiàn).也毫無歧義,因為它的表述是完全正確的.在viewA的寬度=viewB的寬度*3和viewB的寬度=viewA的寬度*2這兩個規(guī)則中并沒有指定到底這兩個寬度是多少,如果都是0那么這條規(guī)則就完全成立.所以我們最終就會看到視圖的約束寬度為0.

2.缺失約束也可能導致丟失視圖

舉個簡單的例子,就以我上面的代碼為例:初始化frame為0,0,30,30.那么我給的約束是高度等于80,距離父視圖left 0,top也是0,那么這個視圖會在self.view上出現(xiàn)嗎.并不會!并且約束也不會報錯.那么視圖為什么不出現(xiàn)啦.還記著我們沒意識圖需要自己添加約束時,講一個屬性置為了NO.translatesAutoresizingMaskIntoConstraints.什么意思啦.當我們設置這個屬性時,默認的初始值(0,0,30,30)已經(jīng)被廢棄了.因為寬度沒有確定,系統(tǒng)不能確定視圖的寬度到底是多少,因而導致寬度為0,導致不可見.

還有就是介紹一下,添加約束的方法吧.

+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullableid)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c

先來介紹幾個參數(shù)吧

item:需要添加約束的視圖

attr1:需要添加約束的屬性,例如left,bottom,top.right,centerx,centerY.等.

relation:分為三種1.NSLayoutRelationLessThanOrEqual小于等于.NSLayoutRelationEqual等于.NSLayoutRelationGreaterThanOrEqual大于等于.

view2:item布局的參考視圖

attr2:view2的left,right等屬性.比如item的left相對于view2的right距離15.

multiplier:比例

constant:固定值,比如設定item的寬高時,如果不與其他視圖參考.view2可以為nil.attr2可以為NSLayoutAttributeNotAnAttribute.

總結:view.attr1 = view.attr2*multiplier+constant.

第一種約束方式就講到這.

VFL

可能很多人對VFL只知其名,但在現(xiàn)實中沒用過.

就在今天讓我們一起研究它,使用它.

可能對于上面的代碼,我們的感覺是代碼量好大啊,布局一個視圖就這么多代碼.那么當時圖較多時,怎么辦.蘋果的工程師也想到了這個問題就出現(xiàn)了我們第二種布局方式:

Visual format language.

它和第一種的約束布局的區(qū)別主要在于代碼量減少了.而且方法更加簡單.先來看一段??吧.

舉例self.view上下左右各64.

代碼


效果

然后我們來分析代碼:

+ (NSArray<__kindofNSLayoutConstraint*> *)constraintsWithVisualFormat:(NSString*)format options:(NSLayoutFormatOptions)opts metrics:(nullableNSDictionary *)metrics views:(NSDictionary *)views;

我們看到這個方法的返回值是一個數(shù)組.數(shù)組中是這個NSLayoutConstraint對象.

參數(shù)format:我們從上面的代碼就可以看出約束都是寫在format中的.an ASCII art-like visual format string

opts:文檔中的大概意思是,屬性的描述和布局的仿效都是對象并且在visual format 字符串中.

metrics:這個字典的鍵必須是visual format字符串 ,他的值必須是NSnumber對象.在visual format字符串中的常量都在這個字段中.

views:visula format字符串中出現(xiàn)的views,保存在這個子彈中,鍵也是visual format字符串.值是view object.

好了看完這個我們應該仔細看看visual format 字符串.

H:|-64-[view]-64-| 這個字符串的意思是:水平方向距離左邊64,右邊64.

V:|-64-[view]-64-| ?這個字符串的意思是:垂直方向舉例上邊64,下邊64.

那么高度和寬度怎么設置啦.

很簡單:

修改約束




V:|-64-[view(==80)] 這個就是距離top 64 高度等于80.設置寬度類似 只需要將V改為H就表示為,水平方向距離左邊64,寬度為80.

VFL最大的缺點是什么啦.他不能表示相對比例和相對居中的約束.


那么兩個視圖的布局該怎么設置啦.


效果


代碼

改有很多關于VFL的用法,這里就不多介紹了,可以查看蘋果官方文檔和(http://study1234.com/autolayoutshen-ru-qian-chu-liu-chun-dai-ma-de-pian-zhi/amp/)


在介紹幾個方法就結束今天的分享了:

//調(diào)用這個方法來判斷視圖的約束是否充分/是否有歧義.

hasAmbiguousLayout

//可以獲得不同方向上的約束

- (NSArray<__kindofNSLayoutConstraint*> *)constraintsAffectingLayoutForAxis:(UILayoutConstraintAxis)axisNS_AVAILABLE_IOS(10_0);

//這個方法會隨機改變視圖的layout到另外一個有效的layout析恢。這樣我們就可以很清楚的看到哪一個layout導致了整體的布局約束出現(xiàn)了錯誤,或者我們應該增加更多的布局約束秧饮。

exerciseAmbiguityInLayout

//讓視圖知道下次布局時需要重新計算.

//[view invalidateIntrinsicContentSize];

//壓縮阻力Size Inspector指定

//代碼設置一個視圖的壓縮阻力.水平軸和垂直軸都需要分別設置.設置的值可以再1到1000之間,默認值為750;

//[view setContentCompressionResistancePriority:500 forAxis:UILayoutConstraintAxisHorizontal];

////代碼設置一個試圖的內(nèi)容吸附優(yōu)先級.默認值為250;

//[view setContentHuggingPriority:501 forAxis:UILayoutConstraintAxisHorizontal];

我在這里先解釋一下壓縮阻力和內(nèi)容吸附.

壓縮阻力.就是指保護其內(nèi)容的方式,壓縮阻力高的視圖可以抵抗壓縮,不允許內(nèi)容被裁減.低的壓縮阻力內(nèi)容會被裁剪.雖然我們空間本身存在著壓縮阻力.但是如果他的優(yōu)先級較低.如果我們改變約束,將其寬度較小.它的內(nèi)容就會被裁剪.要想不被裁剪我們可以手動修改他的重要性.

//[view setContentCompressionResistancePriority:500 forAxis:UILayoutConstraintAxisHorizontal];

內(nèi)容吸附:視圖的大小與內(nèi)容大小匹配的原則.

較高的優(yōu)先級不允許視圖將其伸展.防止出現(xiàn)大片留白.較低的優(yōu)先級允許被拉伸,出現(xiàn)大量留白.

[view setContentHuggingPriority:501 forAxis:UILayoutConstraintAxisHorizontal];

我們可以手動改變其優(yōu)先級.確定是否允許被拉伸.

我們在設置約束時也可以設置約束的優(yōu)先級.

約束的優(yōu)先級
四種優(yōu)先級

1000為最高.50為最低.

好了我們不怎么熟悉的自動布局就先說到這里.后面還會有關于自動布局的分享.例如自動布局的動畫.IB中的自動布局等.

如果喜歡小編,可以點擊關注,我會不定期的更新一些文章,也可以關注我的專題

本人聯(lián)系方式:qq:513961360

vx:掃描下方二維碼:

希望能有志同道合的好友加我.聊技術.聊生活都可以.

vx


email:513961360@qq.com

也可以加我們的qq群希望能與朋友們一起聊天和學習.群里還有很多iOS開發(fā)者,幫助我們解決問題,并且同時學習.

qq群號:580284575

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末映挂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子盗尸,更是在濱河造成了極大的恐慌柑船,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泼各,死亡現(xiàn)場離奇詭異鞍时,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門逆巍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來及塘,“玉大人,你說我怎么就攤上這事蒸苇×子迹” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵溪烤,是天一觀的道長味咳。 經(jīng)常有香客問我,道長檬嘀,這世上最難降的妖魔是什么槽驶? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮鸳兽,結果婚禮上掂铐,老公的妹妹穿的比我還像新娘。我一直安慰自己揍异,他們只是感情好全陨,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衷掷,像睡著了一般辱姨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戚嗅,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天雨涛,我揣著相機與錄音,去河邊找鬼懦胞。 笑死替久,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的躏尉。 我是一名探鬼主播蚯根,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胀糜!你這毒婦竟也來了稼锅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤僚纷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拗盒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怖竭,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年陡蝇,在試婚紗的時候發(fā)現(xiàn)自己被綠了痊臭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哮肚。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖广匙,靈堂內(nèi)的尸體忽然破棺而出允趟,到底是詐尸還是另有隱情,我是刑警寧澤鸦致,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布潮剪,位于F島的核電站,受9級特大地震影響分唾,放射性物質(zhì)發(fā)生泄漏抗碰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一绽乔、第九天 我趴在偏房一處隱蔽的房頂上張望弧蝇。 院中可真熱鬧,春花似錦折砸、人聲如沸看疗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽两芳。三九已至,卻和暖如春睹逃,著一層夾襖步出監(jiān)牢的瞬間盗扇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工沉填, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疗隶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓翼闹,卻偏偏與公主長得像斑鼻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子猎荠,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

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