為什么要了解 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ā)效率。
參考: