FlexBox - YogaKit
FlexBox是一套通用的布局協(xié)議呀潭,YogaKit實(shí)現(xiàn)了這個(gè)協(xié)議莽鸿,iOS端可以使用YogaKit來實(shí)現(xiàn)FlexBox布局听系。FlexBox和UIStackView以及Android的LineLayout有相通的地方虑润,優(yōu)勢(shì)在于FlexBox是跨平臺(tái)的肥荔,功能上也更強(qiáng)一點(diǎn)弥臼。
YogaKit依據(jù)你的設(shè)置計(jì)算出相關(guān)的view的frame,直接設(shè)置frame,所以和AutoLayout可以混合使用宴咧,對(duì)同一個(gè)view進(jìn)行設(shè)置,以AutoLayout的設(shè)置為準(zhǔn)径缅。
YogaKit是從從上往下進(jìn)行計(jì)算的掺栅,使用過程中需要保證flex container的frame有值,這樣它的flex item才會(huì)計(jì)算出frame纳猪,否則都是CGRectZero氧卧。
flex direction
布局延伸的方向,確定了主軸和副軸氏堤,添加的元素沿著主軸的方向進(jìn)行排列沙绝。
-
Row
水平方向從左往右進(jìn)行延伸,主軸為水平方向鼠锈,副軸為豎直方向
-
Row Reverse
水平方向從左往右進(jìn)行延伸闪檬,主軸為水平方向,副軸為豎直方向
-
Column
豎直方向從上往下進(jìn)行延伸购笆,主軸為豎直方向粗悯,副軸為水平方向
-
Column Reverse
豎直方向從下往上進(jìn)行延伸,主軸為豎直方向同欠,副軸為水平方向
justify & align-items
justify 進(jìn)一步明確了元素在主軸方向如何排列样傍,align-items 進(jìn)一步明確了元素在副軸方向如何排列
- flex start
- center
- end
- space between
- space around
- space evenly
- stretch
flex-wrap (適用于父類容器上)
設(shè)置或檢索伸縮盒對(duì)象的子元素超出父容器時(shí)是否換行
padding & margin
iOS 上 padding 對(duì)應(yīng)的是 content inserts,但是 iOS 大部分控件都沒有padding,相信很多人都寫過一個(gè)繼承自 UILabel的控件來提供設(shè)置 content inserts 的控件行您,有了YogaKit,那個(gè)類以后用不上了剪廉。
padding 指的是自身內(nèi)邊距娃循,margin 指的是外邊距,@"H:|-20-[redView]-20-|"斗蒋,這條VFL里的20就是margin捌斧。
display
是否顯示這個(gè)元素笛质,如果為none,則不顯示,也不參與計(jì)算
markDirty
標(biāo)記元素需要重新計(jì)算位置捞蚂,只對(duì)葉子節(jié)點(diǎn)生效妇押。
// 獲取驗(yàn)證碼 -> 重發(fā)
- (void)codeButtonClicked:(UIButton *)button {
[button setTitle:@"重發(fā)" forState:UIControlStateNormal];
button.superview.yoga.marginTop = YGPointValue(0);
[button.yoga markDirty];
[button.superview.yoga applyLayoutPreservingOrigin:YES];
}
flexGrow
flexGrow決定剩余空間怎么分配,含義類似于layout_weight.如果flex item的flexGrow為0姓迅,該flex item不會(huì)占用剩余的空間敲霍。如果多個(gè)flex item的flexGrow不為0,則按flexGrow的值按比例進(jìn)行劃分丁存。
flexShrink
flexShrink決定空間不足肩杈,怎么縮放
align-items、align-self解寝、align-content扩然、
-
align-item
屬性需要施加在 flex 容器上,它規(guī)定的是 flex 容器中所有 item 在副軸中的對(duì)齊方式
// flex item在副軸拉伸填滿剩余空間 layout.alignItems = YGAlignStretch;
-
align-self
屬性則施加在 flex 容器中的 item 上聋伦,允許單個(gè)項(xiàng)目有與其他項(xiàng)目不一樣的對(duì)齊方式夫偶,它覆蓋了外部容器規(guī)定的 align-items 屬性,同樣也只規(guī)定在交叉軸上的對(duì)齊方式
-
align-content
對(duì)比 align-items 和 align-self 直接移動(dòng) item 自身在交叉軸上的基線觉增,align-content 移動(dòng)的是容器自身的 flex line兵拢,并僅對(duì)多行的項(xiàng)目起作用
常見問題
-
Pod
使用
pod 'YogaKit'
安裝的時(shí)候,這個(gè)庫包含了一個(gè)swift文件抑片,對(duì)于純OC的項(xiàng)目卵佛,這會(huì)報(bào)錯(cuò)。可以改成
pod 'IGListKit','2.1.0' pod 'Yoga','1.14.0'
然后將YogaKit的代碼(刪除掉swfit文件后)copy到項(xiàng)目中敞斋,這部分不使用cocopods進(jìn)行管理截汪,這樣改動(dòng)比較小
-
AutoLayout
YogaKit布局設(shè)置的是view的frame,所以如果對(duì)視圖添加約束植捎,視圖最終的大小以約束設(shè)置為準(zhǔn)衙解。
涉及到其他的視圖時(shí),參與計(jì)算的是YogaKit自己計(jì)算出來的view.frame,而不是約束設(shè)置的值焰枢。
實(shí)踐
標(biāo)簽流式布局
- (void)tagLayout {
NSArray *tags = @[@"投資理財(cái)",@"超高收益",@"七日年化收益",@"支付寶",@"微信",@"云閃付",@"花唄"];
UIView *tagBgView = [[UIView alloc] init];
tagBgView.backgroundColor = [UIColor lightGrayColor];
[tagBgView configureLayoutWithBlock:^(YGLayout * _Nonnull layout) {
layout.isEnabled = YES;
layout.flexDirection = YGFlexDirectionRow;
layout.marginTop = YGPointValue(100);
layout.paddingBottom = YGPointValue(10);
layout.width = YGPointValue([UIScreen mainScreen].bounds.size.width);
// 不設(shè)置高度蚓峦,讓高度自適應(yīng)
layout.flexWrap = YGWrapWrap;
}];
[self.view addSubview:tagBgView];
for (NSString *obj in tags) {
UILabel *label = [[UILabel alloc] init];
label.text = obj;
label.backgroundColor = [UIColor orangeColor];
[label configureLayoutWithBlock:^(YGLayout * _Nonnull layout) {
layout.isEnabled =YES;
layout.marginLeft = YGPointValue(10);
layout.marginTop = YGPointValue(10);
}];
[tagBgView addSubview:label];
}
self.view.yoga.isEnabled = YES;
[self.view.yoga applyLayoutPreservingOrigin:NO];
}
<img src="https://i.loli.net/2019/10/10/sdIMwUluPVoCBrN.png" alt="截屏2019-10-10下午5.30.21.png" style="zoom:50%;" />
更新布局
很多時(shí)候,我們的視圖大小是依據(jù)視圖內(nèi)容來決定的,比如按鈕的寬依據(jù)title進(jìn)行調(diào)整济锄,title變了暑椰,寬也要變,暫時(shí)只找到用markDirty實(shí)現(xiàn)的方法荐绝。
FlexBox是一套通用的布局協(xié)議一汽,YogaKit實(shí)現(xiàn)了這個(gè)協(xié)議,iOS端可以使用YogaKit來實(shí)現(xiàn)FlexBox布局低滩。FlexBox和UIStackView以及Android的LineLayout有相通的地方召夹,優(yōu)勢(shì)在于FlexBox是跨平臺(tái)的岩喷,功能上也更強(qiáng)一點(diǎn)。
YogaKit依據(jù)你的設(shè)置計(jì)算出相關(guān)的view的frame,直接設(shè)置frame,所以和AutoLayout可以混合使用监憎,對(duì)同一個(gè)view進(jìn)行設(shè)置纱意,以AutoLayout的設(shè)置為準(zhǔn)。
YogaKit是從從上往下進(jìn)行計(jì)算的鲸阔,使用過程中需要保證flex container的frame有值偷霉,這樣它的flex item才會(huì)計(jì)算出frame,否則都是CGRectZero隶债。
flex direction
布局延伸的方向腾它,確定了主軸和副軸,添加的元素沿著主軸的方向進(jìn)行排列死讹。
-
Row
水平方向從左往右進(jìn)行延伸瞒滴,主軸為水平方向,副軸為豎直方向
-
Row Reverse
水平方向從左往右進(jìn)行延伸赞警,主軸為水平方向妓忍,副軸為豎直方向
-
Column
豎直方向從上往下進(jìn)行延伸,主軸為豎直方向愧旦,副軸為水平方向
-
Column Reverse
豎直方向從下往上進(jìn)行延伸世剖,主軸為豎直方向,副軸為水平方向
justify & align-items
justify 進(jìn)一步明確了元素在主軸方向如何排列笤虫,align-items 進(jìn)一步明確了元素在副軸方向如何排列
- flex start
- center
- end
- space between
- space around
- space evenly
- stretch
flex-wrap (適用于父類容器上)
設(shè)置或檢索伸縮盒對(duì)象的子元素超出父容器時(shí)是否換行
padding & margin
iOS 上 padding 對(duì)應(yīng)的是 content inserts旁瘫,但是 iOS 大部分控件都沒有padding,相信很多人都寫過一個(gè)繼承自 UILabel的控件來提供設(shè)置 content inserts 的控件,有了YogaKit琼蚯,那個(gè)類以后用不上了酬凳。
padding 指的是自身內(nèi)邊距,margin 指的是外邊距遭庶,@"H:|-20-[redView]-20-|"宁仔,這條VFL里的20就是margin。
display
是否顯示這個(gè)元素峦睡,如果為none,則不顯示翎苫,也不參與計(jì)算
markDirty
標(biāo)記元素需要重新計(jì)算位置,只對(duì)葉子節(jié)點(diǎn)生效榨了。
// 獲取驗(yàn)證碼 -> 重發(fā)
- (void)codeButtonClicked:(UIButton *)button {
[button setTitle:@"重發(fā)" forState:UIControlStateNormal];
button.superview.yoga.marginTop = YGPointValue(0);
[button.yoga markDirty];
[button.superview.yoga applyLayoutPreservingOrigin:YES];
}
flexGrow
flexGrow決定剩余空間怎么分配煎谍,含義類似于layout_weight.如果flex item的flexGrow為0,該flex item不會(huì)占用剩余的空間龙屉。如果多個(gè)flex item的flexGrow不為0呐粘,則按flexGrow的值按比例進(jìn)行劃分。
flexShrink
flexShrink決定空間不足,怎么縮放
align-items事哭、align-self、align-content瓜富、
-
align-item
屬性需要施加在 flex 容器上鳍咱,它規(guī)定的是 flex 容器中所有 item 在副軸中的對(duì)齊方式
// flex item在副軸拉伸填滿剩余空間 layout.alignItems = YGAlignStretch;
-
align-self
屬性則施加在 flex 容器中的 item 上,允許單個(gè)項(xiàng)目有與其他項(xiàng)目不一樣的對(duì)齊方式与柑,它覆蓋了外部容器規(guī)定的 align-items 屬性谤辜,同樣也只規(guī)定在交叉軸上的對(duì)齊方式
-
align-content
對(duì)比 align-items 和 align-self 直接移動(dòng) item 自身在交叉軸上的基線,align-content 移動(dòng)的是容器自身的 flex line价捧,并僅對(duì)多行的項(xiàng)目起作用
常見問題
-
Pod
使用
pod 'YogaKit'
安裝的時(shí)候丑念,這個(gè)庫包含了一個(gè)swift文件,對(duì)于純OC的項(xiàng)目结蟋,這會(huì)報(bào)錯(cuò)脯倚。可以改成
pod 'IGListKit','2.1.0' pod 'Yoga','1.14.0'
然后將YogaKit的代碼(刪除掉swfit文件后)copy到項(xiàng)目中,這部分不使用cocopods進(jìn)行管理嵌屎,這樣改動(dòng)比較小
-
AutoLayout
YogaKit布局設(shè)置的是view的frame推正,所以如果對(duì)視圖添加約束,視圖最終的大小以約束設(shè)置為準(zhǔn)宝惰。
涉及到其他的視圖時(shí)植榕,參與計(jì)算的是YogaKit自己計(jì)算出來的view.frame,而不是約束設(shè)置的值。
實(shí)踐
標(biāo)簽流式布局
- (void)tagLayout {
NSArray *tags = @[@"投資理財(cái)",@"超高收益",@"七日年化收益",@"支付寶",@"微信",@"云閃付",@"花唄"];
UIView *tagBgView = [[UIView alloc] init];
tagBgView.backgroundColor = [UIColor lightGrayColor];
[tagBgView configureLayoutWithBlock:^(YGLayout * _Nonnull layout) {
layout.isEnabled = YES;
layout.flexDirection = YGFlexDirectionRow;
layout.marginTop = YGPointValue(100);
layout.paddingBottom = YGPointValue(10);
layout.width = YGPointValue([UIScreen mainScreen].bounds.size.width);
// 不設(shè)置高度尼夺,讓高度自適應(yīng)
layout.flexWrap = YGWrapWrap;
}];
[self.view addSubview:tagBgView];
for (NSString *obj in tags) {
UILabel *label = [[UILabel alloc] init];
label.text = obj;
label.backgroundColor = [UIColor orangeColor];
[label configureLayoutWithBlock:^(YGLayout * _Nonnull layout) {
layout.isEnabled =YES;
layout.marginLeft = YGPointValue(10);
layout.marginTop = YGPointValue(10);
}];
[tagBgView addSubview:label];
}
self.view.yoga.isEnabled = YES;
[self.view.yoga applyLayoutPreservingOrigin:NO];
}
更新布局
很多時(shí)候尊残,我們的視圖大小是依據(jù)視圖內(nèi)容來決定的,比如按鈕的寬依據(jù)title進(jìn)行調(diào)整,title變了淤堵,寬也要變寝衫,暫時(shí)只找到用markDirty實(shí)現(xiàn)的方法。