iOS 上的 FlexBox(箱式) 布局及yogaKit框架使用

為什么要了解 FlexBox?

最近時(shí)不時(shí)的聽到關(guān)于 FlexBox 的聲音锄贷,除了在Weex以及React Native兩個(gè)著名的跨平臺(tái)項(xiàng)目里有用到 FlexBox 外寥裂,AsyncDisplayKit也同樣引入了 FlexBox 。

先說說 iOS 本身提供給我們 2 種布局方式:

Frame,直接設(shè)置橫縱坐標(biāo),并指定寬高。

Auto Layout愧膀,通過設(shè)置相對(duì)位置的約束進(jìn)行布局。

Frame 沒什么太多可說的了谣光,直接制定坐標(biāo)和大小檩淋,設(shè)置絕對(duì)值。

Auto Layout本身用意是好的抢肛,試圖讓我們從 Frame 中解放出來狼钮,擺脫關(guān)于坐標(biāo)和大小的刻板思考方式。轉(zhuǎn)而利用 UI 之間的相對(duì)位置關(guān)系捡絮,設(shè)置對(duì)應(yīng)約束進(jìn)行布局熬芜。

但是Auto Layout好心并未做成好事,它的語法又臭又長(zhǎng)! 至今學(xué)習(xí) iOS 兩年福稳,我使用到原生Auto Layout語法的時(shí)候屈指可數(shù)涎拉。只能靠Masonry這樣的第三方庫來使用它。

Auto Layout 的原理

說完了Auto Layout的使用,再來看看它工作原理鼓拧。

實(shí)際上半火,我們?cè)O(shè)置Auto Layout的約束,就構(gòu)成一系列的條件,成為一個(gè)方程季俩。然后解出 Frame 的坐標(biāo)和大小。

例如店归,我們?cè)O(shè)置一個(gè)名為 A 的 UI :

A.center = super.center

A.width? = 40

A.height = 40

則: A.frame = (super.center.x,super.center.y,40,40)

再設(shè)置一個(gè) B:

B.width? =? A.width

B.height =? A.height

B.top? ? =? A.bottom + 50

B.left? =? A.left

則: B.frame = ( A.x , A.y + A.height + 50 , A.width , A.height )

如圖:

need-to-insert-img

Cassowary

Auto Layout內(nèi)部有專門用來處理約束關(guān)系的算法酪我,我一直以為是蘋果自家研發(fā)的消痛,查閱資料才發(fā)現(xiàn)是來自一個(gè)叫Cassowary的算法秩伞。

Cassowary是個(gè)解析工具包,能夠有效解析線性等式系統(tǒng)和線性不等式系統(tǒng)欺矫,用戶的界面中總是會(huì)出現(xiàn)不等關(guān)系和相等關(guān)系纱新,Cassowary開發(fā)了一種規(guī)則系統(tǒng)可以通過約束來描述視圖間關(guān)系穆趴。約束就是規(guī)則毡代,能夠表示出一個(gè)視圖相對(duì)于另一個(gè)視圖的位置勺疼。

戴銘<深入剖析Auto Layout,分析iOS各版本新增特性>

有興趣的可以進(jìn)一步了解該算法的實(shí)現(xiàn)酪耕。

Frame / Auto Layout / FlexBox 的性能對(duì)比

在對(duì)Auto Layout進(jìn)行一番了解之后,我們很容易得出Auto Layout因?yàn)槎嘤嗟挠?jì)算迂烁,性能差于 Frame 的結(jié)論递鹉。

但究竟差多少呢躏结?FlexBox 的表現(xiàn)又如何呢?

這里根據(jù)從 Auto Layout 的布局算法談性能里的測(cè)試代碼進(jìn)行修改,對(duì) Frame / Auto Layout / FlexBox 進(jìn)行布局黄橘,分段測(cè)算 10 ~ 350 個(gè) UIView 的布局時(shí)間塞关。取 100 次布局時(shí)間的平均值作為結(jié)果,耗時(shí)單位為秒抬探。

結(jié)果如下圖:

need-to-insert-img

雖然測(cè)試結(jié)果難免有偏差小压,但是根據(jù)折線圖可以明顯發(fā)現(xiàn)场航,F(xiàn)lexBox 的布局性能是比較接近 Frame 的廉羔。

60 FPS作為一個(gè) iOS 流暢度的黃金標(biāo)準(zhǔn)憋他,要求布局在 0.0166667 s 內(nèi)完成竹挡,Auto Layout在超過 50 個(gè)視圖的時(shí)候,可能保持流暢就會(huì)開始有問題了梯码。

本次測(cè)試使用的機(jī)器配置如下:

need-to-insert-img

采用 Xcode9.2 ,iPad Pro (12.9-inch)(2nd generation) 模擬器轩娶。

測(cè)試布局的項(xiàng)目代碼上傳在GitHub

FlexBox 是什么鳄抒?

FlexBox是一種 UI 布局方式椰弊,并得到了所有瀏覽器的支持秉版。FlexBox首先是基于盒裝狀型的,F(xiàn)lexible 意味著彈性游桩,使其能適應(yīng)不同屏幕借卧,補(bǔ)充盒狀模型的靈活性铐刘。

FlexBox把每個(gè)視圖,都看作一個(gè)矩形盒子檩禾,擁有內(nèi)外邊距盼产,沿著主軸方向排列勺馆,并且草穆,同級(jí)的視圖之間沒有依賴悲柱。

和Auto Layout類似,F(xiàn)lexBox采用了描述性的語言去進(jìn)行布局嘿般,而不像 Frame 直接用絕對(duì)值坐標(biāo)進(jìn)行布局博个。

彈性布局的主要思想是讓 Flex Container 有能力來改變 Flex Item 的寬度和高度,以填滿可用空間(主要是為了容納所有類型的顯示設(shè)備和屏幕尺寸)的能力往堡。

最重要的是,FlexBox布局與方向無關(guān)虑灰,常規(guī)的布局設(shè)計(jì)缺乏靈活性穆咐,無法支持大型和復(fù)雜的應(yīng)用程序(特別是涉及到方向轉(zhuǎn)變字旭,縮放遗淳、拉伸和收縮等)屈暗。

FlexBox 組成

采用FlexBox布局的元素脂男,稱為Flex Container宰翅。

Flex Container的所有子元素汁讼,稱為Flex Item。


need-to-insert-img

下面會(huì)講一下 FlexBox 里面的一些概念,方便之后進(jìn)行 FlexBox 的使用艰毒。

Flex Container

前面提到了搜囱,F(xiàn)lexBox的一個(gè)特點(diǎn)蜀肘,就是視圖之間扮宠,是沒有依賴的。

Flex Item的排布,就依賴于Flex Container的屬性設(shè)置届案,而不用相互之間進(jìn)行設(shè)置楣颠。

所以先說一下Flex Containner的屬性設(shè)置童漩。

Flex Direction

FlexBox 有一個(gè)主軸(main axis)和側(cè)軸(cross axis)的概念。側(cè)軸垂直于主軸挎春。

它們可以是水平直奋,也可以是垂直脚线。

主軸默認(rèn)為Row, 側(cè)軸默認(rèn)為Column:


need-to-insert-img

Flex Direction決定了Flex Containner內(nèi)的主軸排布方向邮绿。

主軸默認(rèn)為 Row (從左到右):

同時(shí)船逮,也可以設(shè)置 RowRevers(從右至左):

Column(從上到下):

ColumnRevers(從下到上):

Flex Wrap

Flex Wrap 決定在軸線上排列不下時(shí),視圖的換行方式酱鸭。

Flex Wrap 默認(rèn)設(shè)置為 NoWrap垛吗,不會(huì)換行怯屉,一直沿著主軸排列到屏幕之外:

設(shè)置為 Wrap ,則空間不足時(shí)锨络,自動(dòng)換行:

need-to-insert-img

設(shè)置 WrapReverse足删,則換行方向與 Wrap 相反:

need-to-insert-img

這是一個(gè)非常有用的屬性失受。比如典型的九宮格布局,iOS 如果不是用UICollectionView做痪署,那么就需要保存9個(gè)實(shí)例狼犯,然后做判斷悯森,計(jì)算 frame 瓢姻,可維護(hù)性實(shí)在不高音诈。使用UICollectionView可以很好的解決布局细溅,但很多場(chǎng)景并不能復(fù)用喇聊,做起來也不是特別簡(jiǎn)單。

FlexBox 布局的話承疲,用Flex Wrap屬性設(shè)置Wrap就可以直接搞定燕鸽。

移動(dòng)平臺(tái)上相似的方案啊研,比如 Android 的 Linear Layout 和 iOS 的 UIStackView 党远,但卻遠(yuǎn)沒有 FlexBox 強(qiáng)大。

Display

Display 選擇是否計(jì)算它氛驮,默認(rèn)為 Flex. 如果設(shè)置為 None 自動(dòng)忽略該視圖的計(jì)算矫废。

在根據(jù)邏輯顯示 UI 時(shí)蓖扑,比較有用律杠。

比如我們現(xiàn)有的業(yè)務(wù)柜去,需要顯示的騰訊身份標(biāo)示。按照一般做法熬甫,多個(gè) icon 互相連成一排椿肩,根據(jù)身份去設(shè)置不同的距離郑象,同時(shí)隱藏其他 icon ,比較的麻煩厂榛。iOS 最好的辦法是使用 UIStackView 丽惭,這又有版本兼容等問題责掏。而使用 FlexBox 布局,當(dāng)不是某個(gè)身份時(shí)换衬,只要設(shè)置 Display 為 None,就不會(huì)被納入 UI 計(jì)算當(dāng)中瞳浦。

Justify Content

Justify Content用于定義Flex Item在主軸上的對(duì)齊方式:FlexStart(主軸起點(diǎn)對(duì)齊)叫潦,F(xiàn)lexEnd(主軸終點(diǎn)對(duì)齊),Center(居中對(duì)齊)短蜕。

還有SpaceBetween(兩端對(duì)齊):

need-to-insert-img

設(shè)置兩端對(duì)齊忿危,讓Flex Item之間的間隔相等铺厨。

SpaceAround(外邊距相等排列):

need-to-insert-img

讓每個(gè)Flex Item四周的外邊距相等

Align Items

Align Items定義Flex Item在側(cè)軸上的對(duì)齊方式解滓。

Align Items可以和主軸對(duì)齊方式Justify Content一樣,設(shè)置FlexStart ,FlexEnd,Center,SpaceBetween,SpaceAround 洼裤。

Align Items還可以設(shè)置 Baseline(基線對(duì)齊):

need-to-insert-img

如圖所示腮鞍,它是基于Flex Item的第一行文字的基線對(duì)齊移国。

如果Baseline和Flex Item的行內(nèi)軸與側(cè)軸為同一條迹缀,則該值與FlexStart等效祝懂。 其它情況下拘鞋,該值將參與基線對(duì)齊掐禁。

Align Items還可以設(shè)置為 Stretch:

need-to-insert-img

Stretch讓Flex Item拉伸填充整個(gè)Flex Container傅事。Stretch會(huì)使Flex Item的外邊距在遵照對(duì)應(yīng)屬性限制下,盡可能接近所在行或列的尺寸蹭越。

如果Flex Item未設(shè)置數(shù)值,或設(shè)為auto,將占滿整個(gè)Flex Container的高度

Align Content

Align Content也是側(cè)軸在Flex Item里的對(duì)齊方式案训,只不過是以一整個(gè)行强霎,作為最小單位城舞。

注意寞酿,如果Flex Item只有一根軸線(只有一行的Flex Itme)伐弹,該屬性不起作用惨好。

調(diào)整為FlexWrap為Wrap,效果才顯示出來:

Flex Item

在上面說完了Flex Container的屬性,終于說到了Flex Item.Flex Container里的屬性景馁,都是作用于自己包含的Flex Item合住,F(xiàn)lex Item的屬性透葛,都是作用于自己本身僚害,.

AlignSelf

AlignSelf可以讓單個(gè)Flex Item與其它Flex Item有不一樣的對(duì)齊方式萨蚕,覆蓋Align Items屬性蹄胰。

默認(rèn)值為auto裕寨,表示繼承Flex Container的Align Items屬性。如果它本身沒有Flex Container驾窟,則等同于Stretch绅络。

FlexGrow

FlexGrow可以設(shè)置分配剩余空間的比例昨稼。即如何擴(kuò)大。

FlexGrow默認(rèn)值為0霍掺,如果沒有去定義FlexGrow拌蜘,該布局是不會(huì)擁有分配剩余空間權(quán)利的。

例如:

整體寬度 100 , sub1 寬為 10 兔魂,sub2 寬為 20 析校,則剩余空間為 70智玻。

設(shè)置FlexGrow就是分配這 70 寬度的比例吊奢。

再說比例值的問題:

如果所有Flex Item的FlexGrow屬性都為1页滚,如果有剩余空間的話裹驰,則等分剩余空間邦马。

如果一個(gè)Flex Item的FlexGrow屬性為2滋将,其余Flex Item都為1随闽,則前者占據(jù)的剩余空間將比其他Flex Item多1倍掘宪。

FlexShrink

與FlexGrow處理空間剩余相反,F(xiàn)lexShrink用來處理空間不足的情況魏滚。即怎么縮小镀首。

FlexShrink默認(rèn)為1,即如果空間不足鼠次,該項(xiàng)目將縮小

如果所有Flex Item的FlexShrink屬性都為1更哄,當(dāng)空間不足時(shí),都將等比例縮小腥寇。

如果一個(gè)Flex Item的FlexShrink屬性為0成翩,其余Flex Item都為1赦役,則空間不足時(shí)麻敌,F(xiàn)lexShrink為0的前者不縮小。

FlexBasis

FlexBasis定義了在分配多余的空間之前掂摔,F(xiàn)lex Item占據(jù)的main size(主軸空間)术羔。瀏覽器根據(jù)這個(gè)屬性,計(jì)算主軸是否有多余空間乙漓。

FlexBasis的默認(rèn)值為auto聂示,即Flex Item的本來大小。

想了解更多 FlexBox 屬性簇秒,可以參考A Complete Guide to Flexbox

FlexBox 的實(shí)現(xiàn) -- Yoga

最開頭已經(jīng)介紹過鱼喉,F(xiàn)lexBox 布局已經(jīng)應(yīng)用于幾個(gè)知名的開源項(xiàng)目,它們用到的就是來自于 Facebook 的 Yoga.

Yoga是由 C 實(shí)現(xiàn)的 Flexbox 布局引擎趋观,性能和穩(wěn)定性已經(jīng)在各大項(xiàng)目中得到了很好的驗(yàn)證,但不足的是 Yoga 只實(shí)現(xiàn)了 W3C 標(biāo)準(zhǔn)的一個(gè)子集扛禽。

下面將針對(duì) Yoga iOS 上的實(shí)現(xiàn)YogaKit做一些講解。

基于上面對(duì)FlexBox布局的基本了解皱坛,作一些簡(jiǎn)單的布局编曼。

YGLayout

整個(gè) YogaKit 的關(guān)鍵,就在于YGLayout對(duì)象當(dāng)中剩辟。通過YGLayout來設(shè)置布局屬性掐场。

在UIView+Yoga.h的文件里:

/** The YGLayout that is attached to this view. It is lazily created. */@property (nonatomic,readonly, strong) YGLayout *yoga;/** In ObjC land, every time you access `view.yoga.*` you are adding another `objc_msgSend` to your code. If you plan on making multiple changes to YGLayout, it's more performant

to use this method, which uses a single objc_msgSend call.

*/

- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block

NS_SWIFT_NAME(configureLayout(block:));

可以看到一個(gè)名為yoga的YGLayout只讀對(duì)象往扔,和configureLayoutWithBlock:(YGLayoutConfigurationBlock)block方法,并且還使用了NS_SWIFT_NAME()來定義在 Swift 里的方法名熊户。

這樣我們就可以直接使用 UIView 的實(shí)例對(duì)象萍膛,來直接設(shè)置它對(duì)應(yīng)的布局了。

isEnabled

YGLayout.h里是這么定義isEnabled的嚷堡。

/** The property that decides during layout/sizing whether or not styling properties should be applied. Defaults to NO. */@property (nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled;

isEnabled默認(rèn)為NO蝗罗,需要我們?cè)诓季制陂g設(shè)置為YES,來開啟 Yoga 樣式.

applyLayoutPreservingOrigin:

對(duì)于這個(gè)方法蝌戒,頭文件里是這么解釋的:

/** Perform a layout calculation and update the frames of the viewsinthe hierarchy with the results. If the origin is not preserved, the root view's layout results will applied from {0,0}.

*/

- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin

NS_SWIFT_NAME(applyLayout(preservingOrigin:));

簡(jiǎn)單來說串塑,就是用于執(zhí)行 layout 計(jì)算的。所以北苟,一旦在布局代碼完成之后桩匪,就要在根視圖的屬性 yoga 對(duì)象上調(diào)用這個(gè)方法,應(yīng)用布局到根視圖和子視圖友鼻。

布局演示

下面通過實(shí)例來介紹如何使用Yoga進(jìn)行FlexBox布局傻昙。

居中顯示

[self configureLayoutWithBlock:^(YGLayout * layout) {

layout.isEnabled = YES;

layout.justifyContent =? YGJustifyCenter;

layout.alignItems? ? =? YGAlignCenter;

}];

[self.redView configureLayoutWithBlock:^(YGLayout * layout) {

layout.isEnabled = YES;

layout.width=layout.height= 100;

}];

[self addSubview:self.redView];

[self.yoga applyLayoutPreservingOrigin:YES];

效果如下:

need-to-insert-img

我們真正的布局代碼,只用設(shè)置Flex Container的justifyContent和alignItems就可以了.

嵌套布局

讓一個(gè)view略小于其superView,邊距為10:

[self.yellowView configureLayoutWithBlock:^(YGLayout *layout) {

layout.isEnabled = YES;

layout.margin = 10;

layout.flexGrow = 1;

}];

[self.redView addSubview:self.yellowView];

效果如下:

布局代碼只用設(shè)置, View 的margin和flexGrow.

等間距排列

縱向等間距的排列一組 view:

[self configureLayoutWithBlock:^(YGLayout *layout) {? ? ? ? ? ? ? ? layout.isEnabled = YES;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? layout.justifyContent =? YGJustifySpaceBetween;? ? ? ? ? ? ? ? layout.alignItems? ? =? YGAlignCenter;? ? ? ? ? ? }];for( int i = 1 ; i <= 10 ; ++i )? ? ? ? ? ? {? ? ? ? ? ? ? ? UIView *item = [UIView new];? ? ? ? ? ? ? ? item.backgroundColor = [UIColor colorWithHue:( arc4random() % 256 / 256.0 )? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? saturation:( arc4random() % 128 / 256.0 ) + 0.5? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? brightness:( arc4random() % 128 / 256.0 ) + 0.5? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? alpha:1];? ? ? ? ? ? ? ? [item? configureLayoutWithBlock:^(YGLayout *layout) {? ? ? ? ? ? ? ? ? ? layout.isEnabled = YES;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? layout.height? ? = 10*i;? ? ? ? ? ? ? ? ? ? layout.width? ? ? = 10*i;? ? ? ? ? ? ? ? }];? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self addSubview:item];? ? ? ? ? ? }

效果如下:

need-to-insert-img

只要設(shè)置Flex Container的layout.justifyContent = YGJustifySpaceBetween桃移,就可以很輕松的做到。

等間距葛碧,自動(dòng)設(shè)寬

讓兩個(gè)高度為100的view垂直居中,等寬,等間隔排列,間隔為10.自動(dòng)計(jì)算其寬度:

[self configureLayoutWithBlock:^(YGLayout *layout) {

layout.isEnabled = YES;

layout.flexDirection? =? YGFlexDirectionRow;

layout.alignItems? ? =? YGAlignCenter;

layout.paddingHorizontal = 5;

}];

YGLayoutConfigurationBlock layoutBlock =^(YGLayout *layout) {

layout.isEnabled = YES;

layout.height= 100;

layout.marginHorizontal = 5;

layout.flexGrow = 1;

};

[self.redView configureLayoutWithBlock:layoutBlock];

[self.yellowView configureLayoutWithBlock:layoutBlock];

[self addSubview:self.redView];

[self addSubview:self.yellowView];

效果如下 :

我們只要設(shè)置Flex Container的 paddingHorizontal 借杰,以及Flex Item的marginHorizontal,flexGrow 就可以了进泼。并且可以復(fù)用Flex Item的 layout 布局樣式蔗衡。

UIScrollView 排列自動(dòng)計(jì)算 contentSize

在UIScrollView順序排列一些view,并自動(dòng)計(jì)算contentSize:

[self configureLayoutWithBlock:^(YGLayout *layout) {? ? ? ? ? ? ? ? layout.isEnabled = YES;? ? ? ? ? ? ? ? layout.justifyContent =? YGJustifyCenter;? ? ? ? ? ? ? ? layout.alignItems? ? =? YGAlignStretch;? ? ? ? ? ? }];? ? ? ? ? ? ? ? ? ? ? ? UIScrollView *scrollView = [[UIScrollView alloc] init] ;? ? ? ? ? ? scrollView.backgroundColor = [UIColor grayColor];? ? ? ? ? ? [scrollView configureLayoutWithBlock:^(YGLayout *layout) {? ? ? ? ? ? ? ? layout.isEnabled = YES;? ? ? ? ? ? ? ? layout.flexDirection = YGFlexDirectionColumn;? ? ? ? ? ? ? ? layout.height =500;? ? ? ? ? ? }];? ? ? ? ? ? [self addSubview:scrollView];? ? ? ? ? ? UIView *contentView = [UIView new];? ? ? ? ? ? [contentView configureLayoutWithBlock:^(YGLayout * _Nonnull layout) {? ? ? ? ? ? ? ? layout.isEnabled = YES;? ? ? ? ? ? }];for( int i = 1 ; i <= 20 ; ++i )? ? ? ? ? ? {? ? ? ? ? ? ? ? UIView *item = [UIView new];? ? ? ? ? ? ? ? item.backgroundColor = [UIColor colorWithHue:( arc4random() % 256 / 256.0 )? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? saturation:( arc4random() % 128 / 256.0 ) + 0.5? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? brightness:( arc4random() % 128 / 256.0 ) + 0.5? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? alpha:1];? ? ? ? ? ? ? ? [item? configureLayoutWithBlock:^(YGLayout *layout) {? ? ? ? ? ? ? ? ? ? layout.isEnabled = YES;? ? ? ? ? ? ? ? ? ? layout.height? ? = 20*i;? ? ? ? ? ? ? ? ? ? layout.width? ? ? = 100;? ? ? ? ? ? ? ? ? ? layout.marginLeft = 10;? ? ? ? ? ? ? ? }];? ? ? ? ? ? ? ? [contentView addSubview:item];? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? [scrollView addSubview:contentView];? ? ? ? ? ? [scrollView.yoga applyLayoutPreservingOrigin:YES];? ? ? ? ? ? scrollView.contentSize = contentView.bounds.size;

效果如下:

need-to-insert-img

布置UIScrollView主要是使用了一個(gè)中間contentView,起到了計(jì)算scrollview的contentSize的作用。這里要注意的是乳绕,要在scrollview調(diào)用完applyLayoutPreservingOrigin:后進(jìn)行設(shè)置,否則得不到結(jié)果绞惦。

UIScrollView 的用法,目前在網(wǎng)上也沒找到比較官方的示例洋措,完全是筆者自己摸索的济蝉,歡迎知道的大佬指教。

上面所用的示例代碼菠发,已經(jīng)上傳至GitHub

總結(jié)

FlexBox 的確是一個(gè)非常適用于移動(dòng)端的布局方式王滤,語意清晰,性能穩(wěn)定滓鸠,現(xiàn)在移動(dòng)端 UI 視圖越來越復(fù)雜雁乡,尤其是在所有瀏覽器都已經(jīng)支持了 FlexBox 之后,作為移動(dòng)開發(fā)者有必要了解新的解決方式糜俗。

大家在熟練使用 YogaKit 的方式之后踱稍,也可以嘗試自己封裝一套布局代碼曲饱,加快開發(fā)效率。

參考:

Flex 布局教程:語法篇

FlexBox 布局模型

YogaKit

Yoga Tutorial: Using a Cross-Platform Layout Engine

從 Auto Layout 的布局算法談性能

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末珠月,一起剝皮案震驚了整個(gè)濱河市扩淀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桥温,老刑警劉巖引矩,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異侵浸,居然都是意外死亡旺韭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門掏觉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來区端,“玉大人,你說我怎么就攤上這事澳腹≈危” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵酱塔,是天一觀的道長(zhǎng)沥邻。 經(jīng)常有香客問我,道長(zhǎ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
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼恃鞋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起恤浪,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎水由,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赛蔫,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有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
  • 我被黑心中介騙來泰國(guó)打工贝奇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人靠胜。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓掉瞳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親浪漠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陕习,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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