Masonry框架解讀

Masonry是iOS在控件布局中經(jīng)常使用的一個(gè)輕量級(jí)框架悬槽,Masonry讓NSLayoutConstraint使用起來更為簡潔啸蜜。Masonry簡化了NSLayoutConstraint的使用方式毡泻,讓我們可以以鏈?zhǔn)降姆绞綖槲覀兊目丶付s束拼弃。本篇博客的主題不是教你如何去使用Masonry框架的,而是對Masonry框架的源碼進(jìn)行解析凿可,讓你明白Masonry是如何對NSLayoutConstraint進(jìn)行封裝的繁仁,以及Masonry框架中的各個(gè)部分所扮演的角色是什么樣的涉馅。在Masonry框架中,仔細(xì)的品味干貨還是很多的黄虱。Masonry框架是Objective-C版本的稚矿,如果你的項(xiàng)目是Swift語言的,那么就得使用SnapKit布局框架了。SnapKit其實(shí)就是Masonry的Swift版本晤揣,兩者雖然實(shí)現(xiàn)語言不同桥爽,但是實(shí)現(xiàn)思路大體一致。
今天對Masonry框架源碼的解析思路是先對比給一個(gè)View添加同樣的約束時(shí)昧识,使用Masonry與系統(tǒng)原生的區(qū)別钠四。然后就開門見山之間給出Masonry框架主要部分的類圖,從類圖中我們來整體的分析Masonry框架的結(jié)構(gòu)跪楞。然后再由整體到部分逐漸的細(xì)化缀去,窺探其內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)。通過上述步驟甸祭,我們將對Masonry框架的內(nèi)部實(shí)現(xiàn)進(jìn)行詳細(xì)的了解缕碎。其實(shí)Masonry框架是輕量級(jí)的,總共的源碼也沒有多上行池户,但是仔細(xì)的閱讀其實(shí)現(xiàn)細(xì)節(jié)咏雌,還是可以吸取很多實(shí)用的東西的。
首先Masonry在github上的地址是https://github.com/SnapKit/Masonry, 你可以通過上述鏈接Clone到Masonry框架校焦,其中有Masonry框架介紹以及一些Masonry的使用示例赊抖。關(guān)于Masonry的使用方式在今天的博客中就不做過多的贅述了,其具體的使用方式請參考上述github上的鏈接寨典。今天我們就剖析一下Masonry框架的源碼氛雪。

一、Masonry框架與NSLayoutConstraint調(diào)用方式的對比

首先我們NSLayoutConstraint為我們的View添加一個(gè)約束凝赛,然后再給出Masonry的代碼注暗。當(dāng)然在此我們就不說Masonry添加約束的簡潔行了,當(dāng)然好東西是不需要宣傳的墓猎。進(jìn)入該部分的主題,我們要對一個(gè)View添加一個(gè)top約束赚楚,這個(gè)約束關(guān)系我們用表達(dá)式來表示就是“subView.top = superView.top + 10”毙沾。也就是子視圖的top與父視圖的top中間隔著10個(gè)pt。

1. 使用NSLayoutConstraint添加約束

下方這段代碼就是給subView添加了一個(gè)相對于superView的Top約束宠页。一個(gè)View要想確定位置一個(gè)約束是不夠的左胞,所以可想而知,我們要寫多個(gè)下方的這樣的約束來確定一個(gè)View的相對位置举户。其實(shí)下方就是一個(gè)表達(dá)式烤宙,NSLayoutConstraint構(gòu)造器中每個(gè)參數(shù)構(gòu)成這個(gè)表達(dá)式的一個(gè)組成部分。由上到下我們隊(duì)參數(shù)個(gè)個(gè)參數(shù)進(jìn)行解析俭嘁,參數(shù)constraintWithItem用來指定所約束的對象躺枕,在此就是subView。第一個(gè)attribute參數(shù)則指定約束該對象的那個(gè)屬性,在此就是subView的Top屬性拐云。參數(shù)relatedBy用來指定約束關(guān)系罢猪,比如大于等于,小于等于或者等于某個(gè)約束值叉瘩。參數(shù)toItem則指定的是約束相對的對象膳帕,在此是相對superView的,所以此處的參數(shù)是superView薇缅。第二個(gè)attribute參數(shù)就是指定superView的Top屬性危彩。multiplier指定相對約束的倍數(shù)關(guān)系,constant則是約束的偏移量泳桦。
由上到下汤徽,NSLayoutConstraint的構(gòu)造器中的參數(shù)會(huì)構(gòu)成一個(gè)數(shù)學(xué)表達(dá)式,那就是subView.top = superView.top * 1 + 10蓬痒,該表達(dá)式就直觀的給出了subView.top與superView.top的關(guān)系泻骤。經(jīng)下方的代碼我們就為subView添加了一個(gè)相對于superView的Top約束,約束的偏移量是10梧奢。

使用NSLayoutConstraint添加約束

2.使用Masonry添加上述約束

接下來就是Masonry出場的時(shí)刻了狱掂,我們將使用Masonry添加上述約束,其代碼如下亲轨。下方給出了三種設(shè)置方式趋惨,下方三種方式是等價(jià)的,當(dāng)然在Masonry中不知下方三種實(shí)現(xiàn)方式惦蚊。下方Block中的每句話都代表著subView.top = superView.top * 1 + 10的意思器虾,也就是說我們只需要寫這三行代碼中的其中一種即可。使用Masonry的好處一目了然蹦锋,讓你的代碼更為簡潔兆沙。
Masonry框架中支持約束的添加,約束的更新莉掂,約束的重建以及基本動(dòng)畫的實(shí)現(xiàn)等等葛圃。功能還是蠻強(qiáng)大的。在Masonry框架主要中采用了鏈?zhǔn)秸{(diào)用和匿名閉包的方式來簡化約束的添加憎妙。有關(guān)Masonry更為詳細(xì)的使用方式請參見上述Masonry框架的Github鏈接库正,具體使用方式在此就不做過多的贅述了。

使用Masonry添加上述約束

二厘唾、Masonry框架的類結(jié)構(gòu)

通過上述的Masonry的使用方式我們可以看出褥符,UIView的對象可以直接調(diào)用mas_makeConstraints方法來為相應(yīng)的View對象添加約束。因?yàn)閙as_makeConstraints方法位于UIView的View+MASAdditions類目中抚垃,所以UIView的對象可以直接調(diào)用喷楣。同樣在View+MASAdditions類目還有其他方法供UIView的對象使用趟大,稍后會(huì)進(jìn)行詳細(xì)的介紹。
下方就是Masonry框架核心類以及類目之間的關(guān)系抡蛙,下方的類圖是在閱讀Masonry源碼時(shí)畫的护昧,僅此一份,如有雷同純屬巧合粗截。如果下圖中的文字比較小的話惋耙,你可以圖片另存到本地,然后放大后進(jìn)行查看熊昌,廢話少說绽榛,進(jìn)入我們類圖的主題。下方的類圖中沒有包括Masonry框架中的所有的類婿屹,不過所有核心的類都在下方了灭美。我們從左往右依次對下方的類圖進(jìn)行解說。

Masonry框架的類結(jié)構(gòu)

1.View+MASAdditions類目介紹(左邊紅框中的部分)

最左邊那一坨大類昂利,也就是綠框中的部分届腐,就是Masonry框架對UIView的公有類目,也就是源文件中的View+MASAdditions的部分蜂奸,在該類目中為添加了類型為MASViewAttribute的成員屬性(稍后會(huì)介紹MASViewAttribute是個(gè)神馬東西)犁苏。除了添加一系列的成員屬性外,還添加了四個(gè)公有的方法:

  • mas_closestCommonSuperview方法負(fù)責(zé)尋找兩個(gè)視圖的最近的公共父視圖(類比兩個(gè)數(shù)字的最小公倍數(shù))
  • mas_makeConstraints方法負(fù)責(zé)創(chuàng)建安裝約束
  • mas_updateConstraints負(fù)責(zé)更新已經(jīng)存在的約束(若約束不存在就Install)
  • mas_remakeConstraints方法則負(fù)責(zé)移除原來已經(jīng)創(chuàng)建的約束并添加上新的約束扩所。
    上述方式是UIView對象設(shè)置約束主要調(diào)用的方法围详,稍后會(huì)詳細(xì)介紹其實(shí)現(xiàn)方式。

2.MASViewAttribute類的介紹(右邊黃框中的部分)

介紹完用戶直接使用的UIView的公共類目祖屏,接下來我們來看一下用戶看不到的部分助赞,那就是下方類圖中右邊的那一撮類。
右邊的四個(gè)小類的耦合性比較高袁勺,我們先看一下MASViewAttribute類雹食。MASViewAttribute類的結(jié)構(gòu)比較簡單,主要包括三個(gè)屬性期丰,三個(gè)方法婉徘。從MASViewAttribute這個(gè)類名中我們就能看出,這個(gè)類是對UIView和NSLayoutAttribute的封裝咐汞。使用等式來表示就是MASViewAttribute = UIView + NSLayoutAttribute + item。在MASViewAttribute類中的view屬性表示所約束的對象儒鹿,而item就是該對象上可以被約束的部分化撕。
此處的item成員屬性我們稍后要作為NSLayoutConstriant構(gòu)造器中的constraintWithItem與toItem的參數(shù)。當(dāng)然對于UIView來說該item就是UIView本身约炎。而對于UIViewController植阴,該出Item就topLayoutGuide蟹瘾,bottomLayoutGuide稍后會(huì)給出詳細(xì)的介紹。該類中除了兩個(gè)構(gòu)造器外還有一個(gè)isSizeAttribute方法掠手,該方法用來判斷MASViewAttribute類中的layoutAttribute屬性是否是NSLayoutAttributeWidth或者NSLayoutAttributeHeight憾朴,如果是Width或者Height的話,那么約束就添加到當(dāng)前View上喷鸽,而不是添加在父視圖上众雷。

3.MASViewConstraint的介紹(右邊黃框中的部分)

接著我們看一下MASViewConstraint類,該類是對NSLayoutConstriant類的進(jìn)一步封裝做祝。MASViewConstraint做的最核心的一件事情就是初始化NSLayoutConstriant對象砾省,并將該對象添加在相應(yīng)的視圖上。因?yàn)镹SLayoutConstriant在初始化時(shí)需要NSLayoutAttribute和所約束的View混槐,而MASViewAttribute正是對View與NSLayoutAttribute進(jìn)行的封裝编兄,所以MASViewConstraint類要依賴于MASViewAttribute類,兩者的關(guān)系如下所示声登。

由下方的類圖我們可以看出MASConstraint是MASViewConstraint的父類狠鸳,MASConstraint是一個(gè)抽象類,不可被實(shí)例化悯嗓。我們可以將MASConstraint看做是一個(gè)接口或者協(xié)議件舵。MASConstraint抽象類還有一個(gè)子類,也就是MASViewConstraint的兄弟類MASCompositeConstraint绅作,從MASCompositeConstraint的命名中我們就可以看出來MASCompositeConstraint是約束的一個(gè)組合芦圾,也就是其中存儲(chǔ)的是一系列的約束。MASCompositeConstraint類的結(jié)構(gòu)比較簡單俄认,其核心就是一個(gè)存儲(chǔ)MASViewConstraint對象的數(shù)組个少,MASCompositeConstraint就是對該數(shù)組的一個(gè)封裝而已。

4.工廠類MASConstraintMaker(中間綠框中的部分)

兩邊的看完了眯杏,接下來我們來看一下中間的部分夜焦,也就是MASConstraintMaker類。該類就是一個(gè)工廠類岂贩,負(fù)責(zé)創(chuàng)建MASConstraint類型的對象(依賴于MASConstraint接口茫经,而不依賴于具體實(shí)現(xiàn))。在UIView的View+MASAdditions類目中就是調(diào)用的MASConstraintMaker類中的一些方法萎津。上述我們在使用Masonry給subView添加約束時(shí)卸伞,mas_makeConstraints方法中的Block的參數(shù)就是MASConstraintMaker的對象。用戶可以通過該Block回調(diào)過來的MASConstraintMaker對象給View指定要添加的約束以及該約束的值锉屈。該工廠中的constraints屬性數(shù)組就記錄了該工廠創(chuàng)建的所有MASConstraint對象荤傲。
Masonry框架中的核心類以及類目間的關(guān)系就介紹完了,下方就是核心類和類目的類圖颈渊。下方將會(huì)逐步的窺探其代碼實(shí)現(xiàn)遂黍。

三终佛、View+MASAdditions源碼解析

我們先對UIView的公共類目View+MASAdditions中的源碼進(jìn)行解析,也就是對應(yīng)著上方紅框中的部分雾家。用戶是通過 View+MASAdditions中的東西來為View添加約束的铃彰,View+MASAdditions也就是Masonry框架與外界交互的通道。該部分主要對View+MASAdditions源碼進(jìn)行解析芯咧,先介紹其成員屬性牙捉,然后介紹主要的方法。進(jìn)入該部分的主題唬党。

1.View+MASAdditions主要成員屬性及getter方法

下方截圖中是View+MASAdditions類目中的部分成員屬性鹃共,其他的也與下方類似,這些屬性都是MASViewAttribute類型的驶拱。以下方的mas_left成員屬性為例霜浴,因?yàn)镸ASViewAttribute是View與NSLayoutAttribute的合體,所以mas_left就代表著當(dāng)前View的NSLayoutAttributeLeft屬性蓝纲,也就是mas_left存儲(chǔ)的是當(dāng)前View的NSLayoutAttributeLeft屬性阴孟。同理,mas_top就代表著當(dāng)前View的NSLayoutAttributeTop屬性税迷,其他成員屬性也是一樣永丝。


View+MASAdditions主要成員屬性

通過上述成員屬性所對應(yīng)的getter方法,我們可以對其中所存儲(chǔ)的內(nèi)容一目了然箭养。下方是mas_left慕嚷、mas_top和mas_right成員屬性所對應(yīng)的getter方法,其中所做的事情就是對MASViewAttibute進(jìn)行實(shí)例化毕泌,在實(shí)例化時(shí)指定當(dāng)前視圖所對應(yīng)的LayoutAttribute喝检。也就是mas_left = self + NSLayoutAttributeLeft, mas_top = self +NSLayoutAttributeTop, 當(dāng)然此處的self就代表當(dāng)前視圖。

mas_left撼泛、mas_top和mas_right成員屬性所對應(yīng)的getter方法

2.mas_makeConstraints方法解析

上面在介紹類圖的時(shí)候也提到了挠说,用戶是通過調(diào)用mas_makeConstraints方法來為當(dāng)前視圖添加約束的。下方代碼就是mas_makeConstraints函數(shù)的代碼實(shí)現(xiàn)愿题,根據(jù)個(gè)人理解损俭,對每行代碼進(jìn)行了中文注釋,接下來我們來好好的看一下該函數(shù)的結(jié)構(gòu).

  • mas_makeConstraints方法的返回值是一個(gè)數(shù)組(NSArray),數(shù)組中所存放的就是當(dāng)前視圖中所添加的所有約束。因?yàn)镸asonry框架對NSLayoutConstraint封裝成了MASViewConstraint潘酗,所有此處數(shù)組中存儲(chǔ)的是MASViewConstraint對象杆兵。
  • 接下來來看mas_makeConstraints的參數(shù),mas_makeConstraints測參數(shù)是一個(gè)類型為void(^)(MASConstraintMaker *)的匿名Block(也就是匿名閉包)仔夺,該閉包的返回值為Void, 并且需要一個(gè)MASConstraintMaker工廠類的一個(gè)對象拧咳。該閉包的作用就是可以讓mas_makeConstraints方法通過該block給MASConstraintMaker工廠類對象中的MAConstraint屬性進(jìn)行初始化。請參加下方block的使用囚灼。
  • 在mas_makeConstraints方法體中骆膝,首先將當(dāng)前View的translatesAutoresizingMaskIntoConstraints屬性設(shè)置成No, 然后創(chuàng)建了一個(gè)MASConstraintMaker工廠類對象constraintMaker,然后通過block將constraintMaker對象回調(diào)給用戶讓用戶對constraintMaker中的MAConstraint類型的屬性進(jìn)行初始化灶体。換句話說block中所做的事情就是之前用戶設(shè)置約束是所添加的代碼阅签,比如make.top(@10) == ( constraintMaker.top = 10 )。
  • 最后調(diào)用constraintMaker的install方法對用戶指定的約束進(jìn)行安裝蝎抽。
      


    mas_makeConstraints方法解析

3.mas_updateConstraints與mas_remakeConstraints函數(shù)的解析

這兩個(gè)函數(shù)內(nèi)部的實(shí)現(xiàn)與mas_makeConstraints類似政钟,就是多了一個(gè)屬性的設(shè)置。
mas_updateConstraints中將constraintMaker中的updateExisting設(shè)置為YES, 也就是說當(dāng)添加約束時(shí)要先檢查約束是否已經(jīng)被安裝了樟结,如果被添加了就更新养交,如果沒有被添加就添加。
而mas_remakeConstraints中所做的事情是將removeExisting屬性設(shè)置成YES, 表示將當(dāng)前視圖上的舊約束進(jìn)行移除瓢宦,然后添加上新的約束碎连。
 


4、mas_closestCommonSuperview方法解析

mas_closestCommonSuperview方法負(fù)責(zé)計(jì)算出兩個(gè)視圖的公共父視圖驮履,這個(gè)類似求兩個(gè)數(shù)字的最小公倍數(shù)鱼辙。下方的代碼就是尋找兩個(gè)視圖的公共父視圖,當(dāng)然是最近的那個(gè)公共父視圖玫镐。如果找到了就返回倒戏,如果找不到就返回nil。尋找兩個(gè)視圖的公共父視圖對于約束的添加來說是非常重要的恐似,因?yàn)橄鄬Φ募s束是添加到其公共父視圖上的杜跷。比如舉個(gè)列子 viewA.left = viewB.right + 10, 因?yàn)槭莢iewA與viewB的相對約束,那么約束是添加在viewA與viewB的公共父視圖上的矫夷,如果viewB是viewA的父視圖葛闷,那么約束就添加在viewB上從而對viewA起到約束作用。
  

mas_closestCommonSuperview方法解析

四口四、順藤摸瓜孵运,解析約束工廠類MASConstraintMaker

上一個(gè)部分我們分析了View+MASAdditions類目,在該類目中主要使用到了約束的工廠類MASConstraintMaker蔓彩,接下我們就來窺探一下MASConstraintMaker中的內(nèi)容治笨。MASConstraintMaker之所以成為約束工廠類,因?yàn)镸ASConstraintMaker賦值創(chuàng)建NSLayoutConstraint對象赤嚼,因?yàn)镸asonry將NSLayoutConstraint類進(jìn)一步封裝成了MASViewConstraint旷赖,所以MASConstraintMaker是負(fù)責(zé)創(chuàng)建MASViewConstraint的對象,并調(diào)用MASViewConstraint對象的Install方法將該約束添加到相應(yīng)的視圖中更卒。

1.MASConstraintMaker中的核心公有屬性等孵。

下方截圖是MASConstraintMaker中的部分屬性,可以看出下方的屬性都是MSAConstriant類型蹂空,MSAConstriant是抽象類俯萌,所以下方成員變量存儲(chǔ)的實(shí)質(zhì)上是MSAConstriant子類MASViewConstraint的對象果录。MASConstraintMaker就負(fù)責(zé)對MASViewConstraint進(jìn)行實(shí)例化。一句話解釋MASViewConstraint咐熙,MASViewConstraint = View + NSLayoutConstraint + Install弱恒。稍后會(huì)給出MASViewConstraint具體技術(shù)細(xì)節(jié)的實(shí)現(xiàn)。在MASConstraintMaker還有一個(gè)私有數(shù)組constraints棋恼,該數(shù)組就用來記錄以及創(chuàng)建的Constraint對象返弹。

MASConstraintMaker中的部分屬性

2.MASConstraintMake中的工廠方法解析

工廠類肯定有工廠方法,接下來我們來介紹MASConstraintMaker中的工廠方法方法爪飘,上面每個(gè)MASConstraint類型的屬性都對應(yīng)一個(gè)getter方法义起,在getter方法中都會(huì)調(diào)用addConstraintWithLayoutAttribute方法,而addConstraintWithLayoutAttribute會(huì)調(diào)用第二個(gè)截個(gè)圖中的方法师崎,而截圖中的這個(gè)方法就是MASConstraintMaker工廠類的工廠方法默终,根據(jù)提供的參數(shù)創(chuàng)建MSAViewConstraint對象,如果該函數(shù)的第一個(gè)參數(shù)不為空的話就會(huì)將新創(chuàng)建的MSAViewConstraint對象與參數(shù)進(jìn)行合并組合成MASCompositeConstraint類(MASCompositeConstraint本質(zhì)上是MSAViewConstraint對象的數(shù)組)的對象抡诞。
  

MASConstraintMaker工廠類的工廠方法

下方就是MASConstraintMaker工廠類的工廠方法穷蛹,負(fù)責(zé)創(chuàng)建MASConstraint類的對象。下方的方法可以創(chuàng)建MASCompositeConstraint和MASViewConstraint對象昼汗,上面也說了肴熏,MASCompositeConstraint對象就是MASViewConstraint對象的數(shù)組。下方創(chuàng)建完MASConstraint類的相應(yīng)的對象后顷窒,會(huì)把該創(chuàng)建的對象添加進(jìn)MASConstraintMaker工廠類的私有constraints數(shù)組蛙吏,來記錄該工廠對象創(chuàng)建的所有約束。newConstraint.delegate = self; 這句話是非常重要的鞋吉,由于為MASConstraint對象設(shè)置了代理鸦做,所以才支持鏈?zhǔn)秸{(diào)用(例如:maker.top.left.right.equalTo(@10))。
關(guān)于鏈?zhǔn)秸{(diào)用咱就以maker.top.left.right為例谓着。此處的maker, 就是我們的MASConstraintMaker工廠對象恢着,maker.top會(huì)返回帶有NSLayoutAttributeTop屬性的MASViewConstraint類的對象谊路,我們先做一個(gè)轉(zhuǎn)換:newConstraint = maker.top辅鲸。那么maker.top.left 等價(jià)于newConstraint.left酱床,需要注意的是此刻調(diào)用的left方法就不在是我們工廠MASConstraintMaker中的left的getter方法了,而是被換到MASViewConstraint類中的left屬性的getter方法了舷蒲。給newConstraint設(shè)置代理就是為了可以在MASViewConstraint類中通過代理來調(diào)用MASConstraintMaker工廠類的工廠方法來完成創(chuàng)建耸袜。下方代碼如果沒有newConstraint.delegate = self;代理的設(shè)置的話,那就不支持鏈?zhǔn)秸{(diào)用牲平。
說了這么多堤框,總結(jié)一下,如果你調(diào)用maker.top, maker.left等等這些方法都會(huì)調(diào)用下方的工廠方法來創(chuàng)建相應(yīng)的MASViewConstraint對象,并記錄在工廠對象的約束數(shù)組中蜈抓。之所以能鏈?zhǔn)秸{(diào)用启绰,就是講當(dāng)前的工廠對象指定為MASViewConstraint對象的代理,所以一個(gè)MASViewConstraint對象就可以通過代理來調(diào)用工廠方法來創(chuàng)建另一個(gè)新的MASViewConstraint對象了资昧,此處用到了代理模式酬土。

MASConstraintMaker工廠類的工廠方法

3. 工廠類中的install方法

雖然我們將MASConstraintMake視為工廠類,不過該工廠類的功能不僅僅創(chuàng)建MASConstraint的對象格带,還負(fù)責(zé)調(diào)用MASConstraint對象的install方法來將相應(yīng)的約束安裝到想要的視圖上。在MASConstraintMake類中的install方法就是遍歷工廠對象所創(chuàng)建所有約束對象并調(diào)用每個(gè)約束對象的install方法來進(jìn)行約束的安裝刹枉。下方就是該工廠類中的install方法叽唱。
在安裝約束時(shí),如果self.removeExisting == Yes, 那么用戶就通過mas_remakeConstraints方法調(diào)用的install方法微宝,就先將原來的約束進(jìn)行移除掉棺亭,然后添加上新的約束。在安裝約束時(shí)蟋软,將updateExisting賦值給每個(gè)約束镶摘,每個(gè)約束在調(diào)用本身的install方法時(shí)會(huì)判斷是否更新。下方就是MASConstraintMake的install方法的實(shí)現(xiàn)和注釋岳守。

工廠類中的install方法

五凄敢、繼續(xù)順藤摸瓜,解析MASViewConstraint

MASConstraintMaker工廠類所創(chuàng)建的對象實(shí)質(zhì)上是MASViewConstraint類的對象湿痢。而MASViewConstraint類實(shí)質(zhì)上是對MASLayoutConstraint的封裝涝缝,進(jìn)一步說MASViewConstraint負(fù)責(zé)為MASLayoutConstraint構(gòu)造器組織參數(shù)并創(chuàng)建MASLayoutConstraint的對象,并將該對象添加到相應(yīng)的視圖中譬重。接下來我們將對MASViewConstraint類中的內(nèi)容進(jìn)行解析拒逮。

1.MASViewConstraint的對象鏈?zhǔn)秸{(diào)用探索

MASViewConstraint的對象是支持鏈?zhǔn)秸{(diào)用的,比如constraint.top.left.equalTo(superView).offset(10); 上面的這種方式就是鏈?zhǔn)秸{(diào)用臀规,而且像equalTo(superView)這種形式也不是Objective-C中函數(shù)調(diào)用的方式滩援,在Objective-C中是通過[]來調(diào)用函數(shù)的,而此處使用了()塔嬉。接下來講分析這種鏈?zhǔn)降恼{(diào)用是如何實(shí)現(xiàn)的玩徊。
在MASViewConstraint類中的left, top等約束的getter方法都會(huì)調(diào)用下方的這個(gè)方法,而這個(gè)方法中所做的事情就是通過代理來調(diào)用工廠中的工廠方法來根據(jù)LayoutAttribute創(chuàng)建相應(yīng)的MASConstraint對象邑遏。


而像offset(10)這種調(diào)用方式是如何實(shí)現(xiàn)的呢佣赖?我們知道在OC中是不能通過小括號(hào)來調(diào)用方法的,那邊閉包是可以的记盒,不過offset()不是一個(gè)簡單的閉包憎蛤。在offset()的代碼分析后我們不難發(fā)現(xiàn)offset() = offset + (); offset的代碼實(shí)現(xiàn)方式如下。offset是一個(gè)getter方法的名,offset函數(shù)的返回值是一個(gè)匿名Block, 也就是offset后邊的()俩檬。這個(gè)匿名閉包有一個(gè)CGFloat的參數(shù)萎胰,為了支持鏈?zhǔn)秸{(diào)用該匿名閉包返回一個(gè)MASConstraint的對象。

2.install方法解析

MASViewConstraint中install方法負(fù)責(zé)創(chuàng)建MASLayoutConstraint對象棚辽,并且將該對象添加到相應(yīng)的View上技竟。下方代碼就是install中根據(jù)MASViewConstraint所收集的參數(shù)來創(chuàng)建NSLayoutConstraint對象,下方的MASLayoutConstraint其實(shí)就是NSLayoutConstraint的別名屈藐。下方就是調(diào)用系統(tǒng)的NSLayoutConstraint為創(chuàng)建相應(yīng)的約束對象榔组,下方的構(gòu)造器與第一部分中的NSLayoutConstraint一致。

創(chuàng)建完約束對象后联逻,我們要尋找該約束添加到那個(gè)View上搓扯。下方的代碼段就是獲取接收該約束對象的視圖。如果是兩個(gè)視圖相對約束包归,就獲取兩種的公共父視圖锨推。如果添加的是Width或者Height,那么久添加到當(dāng)前視圖上公壤。如果既沒有指定相對視圖换可,也不是Size類型的約束,那么就將該約束對象添加到當(dāng)前視圖的父視圖上厦幅。代碼實(shí)現(xiàn)如下:


創(chuàng)建完約束對象沾鳄,并且找到承載約束的視圖后,接下來就是將該約束添加到該視圖上慨削。子啊添加約束是我們要判斷是不是對約束的更新洞渔,如果是對約束的更新的話就先獲取已經(jīng)存在的約束并對該約束進(jìn)行更新,如果被更新的約束不存在就進(jìn)行添加缚态。添加成功后我們將通過mas_installedConstraints屬性記錄一下本安裝的約束磁椒。mas_installedConstraints是通過運(yùn)行時(shí)為UIView關(guān)聯(lián)的一個(gè)NSMutable類型的屬性,用來記錄約束該視圖的所有約束玫芦。

3.UIView的私有類目UIView+MASConstraints

在MASViewConstraint中定義了一個(gè)UIView的私有類目UIView+MASConstraints浆熔,該類目的功能為UIView通過運(yùn)行時(shí)來關(guān)聯(lián)一個(gè)NSMutableSet類型的mas_installedConstraints屬性。該屬性中記錄了約束該View的所有約束桥帆。代碼實(shí)現(xiàn)如下医增。


因?yàn)槠邢蓿裉斓牟┛途拖鹊竭@兒老虫。對Masonry框架中的代碼不可能在本篇博客中都進(jìn)行一一介紹叶骨。不過在github上分享了一個(gè)Masonry的一個(gè)使用Demo以及源碼解析的工程。其中對Masonry的關(guān)鍵代碼都進(jìn)行了說明與注釋祈匙。下方是其github分享鏈接忽刽。
github分享地址:https://github.com/lizelu/MasonryDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末天揖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子跪帝,更是在濱河造成了極大的恐慌今膊,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伞剑,死亡現(xiàn)場離奇詭異斑唬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)黎泣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門恕刘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抒倚,你說我怎么就攤上這事雪营。” “怎么了衡便?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長洋访。 經(jīng)常有香客問我镣陕,道長,這世上最難降的妖魔是什么姻政? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任呆抑,我火速辦了婚禮,結(jié)果婚禮上汁展,老公的妹妹穿的比我還像新娘鹊碍。我一直安慰自己,他們只是感情好食绿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布侈咕。 她就那樣靜靜地躺著,像睡著了一般器紧。 火紅的嫁衣襯著肌膚如雪耀销。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天铲汪,我揣著相機(jī)與錄音熊尉,去河邊找鬼。 笑死掌腰,一個(gè)胖子當(dāng)著我的面吹牛狰住,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播齿梁,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼催植,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起查邢,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤蔗崎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后扰藕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缓苛,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年邓深,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了未桥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芥备,死狀恐怖冬耿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情萌壳,我是刑警寧澤亦镶,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站袱瓮,受9級(jí)特大地震影響缤骨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尺借,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一绊起、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧燎斩,春花似錦虱歪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至谨读,卻和暖如春局装,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劳殖。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工铐尚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哆姻。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓宣增,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矛缨。 傳聞我的和親對象是個(gè)殘疾皇子爹脾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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

  • Masonry是iOS在控件布局中經(jīng)常使用的一個(gè)輕量級(jí)框架帖旨,Masonry讓NSLayoutConstraint使...
    丘比沙拉閱讀 3,181評(píng)論 2 19
  • Masonry是一個(gè)輕量級(jí)的布局框架,擁有自己的描述語法灵妨,采用更優(yōu)雅的鏈?zhǔn)秸Z法封裝自動(dòng)布局解阅,簡潔明了并具有高可讀性...
    3dcc6cf93bb5閱讀 1,768評(píng)論 0 1
  • (一)Masonry介紹 Masonry是一個(gè)輕量級(jí)的布局框架 擁有自己的描述語法 采用更優(yōu)雅的鏈?zhǔn)秸Z法封裝自動(dòng)布...
    木易林1閱讀 2,338評(píng)論 0 3
  • 從ReflectiveFeign中看到實(shí)現(xiàn)將接口方法解析成Rest請求的核心邏輯在這行代碼: MethodHand...
    無式閱讀 317評(píng)論 0 0
  • 一直覺得自己有心理問題,不知道這本身是不是就是個(gè)心理問題泌霍。 可能是冥冥之中吧货抄,讓我遇到了這本關(guān)于心理的書――《遇見...
    溫迪畫畫閱讀 820評(píng)論 11 12