Masonry實現原理並沒有那麼可怕

2021-09-11 12:08:36 字數 4653 閱讀 1911

想必在afnetworking之後,masonry成了廣大ios開發者日常開發不可或缺的三方庫之一。它的使用真的非常簡單,例如:

[greenview makeconstraints:^(masconstraintmaker *make) ];

複製**

1.makeconstraints:

2.make

3.left、right、height...

4.equalto()

- (nsarray *)mas_makeconstraints:(void(^)(masconstraintmaker *))block 

複製**

translatesautoresizingmaskintoconstraints,官方解釋大致為:預設情況下它是yes,即viewautoresizing mask會自動成為它的布局。如果我們希望手動布局,需要將它設為no

從鏈式呼叫make.top.equalto...,我們可以看出,make中定義了這些約束屬性,它們是這樣實現的:

// step 1

- (masconstraint *)left

// step 2

- (masconstraint *)addconstraintwithlayoutattribute:(nslayoutattribute)layoutattribute

// step 3

- (masconstraint *)constraint:(masconstraint *)constraint addconstraintwithlayoutattribute:(nslayoutattribute)layoutattribute

if (!constraint)

return newconstraint;

}複製**

masviewattribute從實現檔案中得知,masviewattribute = view + nslayoutattribute + item,這是乙個可變元組,儲存了view和與它相關的約束資訊。

masviewconstraint這就是乙個約束,它包含firstviewattributesecondviewattribute

由step2可知,單純的約束屬性在該方法下的第乙個引數都是nil,所以我們先直接看這種情況下的step3的執**況。它被加入了乙個約束陣列中。

if (!constraint) 

複製**

4)鏈式呼叫的實現我們知道masonry鏈式呼叫是它廣受好評的優點之一。那麼,是如何做到make.top.left這樣的操作呢? 由step3得知,make.top的返回型別是masviewconstraint,那masviewconstraint中是如何呼叫到left的呢? 從masviewconstraint的父類masconstraint可以看到,這裡也定義了所有的布局屬性,而這些布局屬性的實現方式,如下,例:

// masconstraint.m

- (masconstraint *)top

// masviewconstraint.m

- (masconstraint *)addconstraintwithlayoutattribute:(nslayoutattribute)layoutattribute

複製**

masviewconstraint把這個方法的具體實現委託給了**方法。而在step3中,這個**正是masconstraintmaker。不同的是,此時,step2方法的引數不在是nil了,而是當前約束屬性。這也是的step3的處理邏輯不一樣了。(回到step3中再看看!)此時,mascompositeconstraint登場了,它是乙個約束組合。以make.top.left...為例,這個約束組合包含了topleft,並且呼叫了shouldbereplacedwithconstraint:方法,如下:

- (void)constraint:(masconstraint *)constraint shouldbereplacedwithconstraint:(masconstraint *)replacementconstraint 

複製**

make.top.left...為例,這個方法找到了之前儲存top約束的位置,並替換成了約束組合。最終,topleft就一起被加入和make的約束陣列中。

從上文看,我們已經拿到了所有的約束。這些約束是如何加入到檢視上的?來看看install方法。 摘錄一下masconstraintmaker中的install

- (nsarray *)install 

}nsarray *constraints = self.constraints.copy;

for (masconstraint *constraint in constraints)

[self.constraints removeallobjects];

return constraints;

}複製**

make的處理相對簡單,再看看masviewconstraint本身是如何install的。由於方法太長,我不貼上完整的**了(分開來會比較容易看懂)。大致的流程如下: 1.如何約束是設定widthheight,這是檢視自身的屬性,則把當前檢視的父檢視作為關聯檢視(**中為secondlayoutitem)。即這兩個約束是相對于父檢視設定的。

2.如果布局上存在相對檢視,即通常寫法中的equalto(someview.mas_top)這樣,則找到這2個檢視最近的公共父檢視,並把約束新增在這個父檢視上。**如下:

if (self.secondviewattribute.view)  else

if (self.firstviewattribute.issizeattribute) else

複製**

3.最後,如果是更新約束操作,則找出需要更新的約束單獨修改;否則,為檢視新增約束,並記錄在mas_installedconstraints中。

到這裡,約束的新增已經完全梳理明白了。

還是得看具體實現方法:

- (masconstraint * (^)(id, nslayoutrelation))equaltowithrelation 

mascompositeconstraint *compositeconstraint = [[mascompositeconstraint alloc] initwithchildren:children];

compositeconstraint.delegate = self.delegate;

[self.delegate constraint:self shouldbereplacedwithconstraint:compositeconstraint];

return compositeconstraint;

} else

};}複製**

這裡就比較好理解了,如果傳入的是約束陣列,則把他包裝成mascompositeconstraint,以同樣的方式加入到makeconstraints中。如果是單個約束,則將其設為secondviewattribute,用於install的時候使用。

1.masconstraintmaker作為工廠,生產乙個個masviewconstraint約束物件。 2.masviewconstraintmascompositeconstraint繼承於抽象類masconstraint,為我們提供了高度封裝的約束物件 3.view+masadditions這個uiview的擴充套件是masonry與外界互動的介面類,這樣很好的把複雜的約束邏輯封裝在內部管理,又提供了簡單的api供使用者使用。

你看懂了嘛~

React Native 並沒有死!

雖然廠商紛紛棄react native而去,但我相信facebook不會輕言放棄,廠商的離去反而會讓facebook更好的審視react native優缺點,在這次的大規模重構中,解決廠商提出的一些問題,並且會吸收flutter和vue.js的優點,從而使react native與原生架構結合得更好...

ChainLink的VRF並沒有想象中那麼好

很早的時候,chainlink就聲稱自己做出了vrf功能。我當時也是很興奮,去實操了一把,還專門寫了一篇文章記錄這件事。先看這篇chainlink官方發的文章 簡而言之,智慧型合約會向 chainlink 或 chainlink 預言機網路提供乙個 seed 來請求隨機數。這個 seed 是預言機無...

AsyncTask的execute並沒有立即執行

原因不講了,也講不清楚,解決方案就是利用executeonexecutor設定自己的佇列,從而在舊頁面關閉前能及時清理當前頁面發出的資料請求 ps tasks為乙個arraylist,用來儲存當前介面所有產生的task,executeonexecutor能清除等待中的task們,cancle tru...