FlexBox - YogaKit

FlexBox - YogaKit

FlexBox是一套通用的布局協(xié)議,YogaKit實現(xiàn)了這個協(xié)議,iOS端可以使用YogaKit來實現(xiàn)FlexBox布局。FlexBox和UIStackView以及Android的LineLayout有相通的地方,優(yōu)勢在于FlexBox是跨平臺的,功能上也更強一點。

YogaKit依據(jù)你的設(shè)置計算出相關(guān)的view的frame,直接設(shè)置frame,所以和AutoLayout可以混合使用,對同一個view進(jìn)行設(shè)置,以AutoLayout的設(shè)置為準(zhǔn)。

YogaKit是從從上往下進(jìn)行計算的,使用過程中需要保證flex container的frame有值,這樣它的flex item才會計算出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è)置或檢索伸縮盒對象的子元素超出父容器時是否換行

padding & margin

iOS 上 padding 對應(yīng)的是 content inserts,但是 iOS 大部分控件都沒有padding,相信很多人都寫過一個繼承自 UILabel的控件來提供設(shè)置 content inserts 的控件,有了YogaKit,那個類以后用不上了。

padding 指的是自身內(nèi)邊距,margin 指的是外邊距,@"H:|-20-[redView]-20-|",這條VFL里的20就是margin。

display

是否顯示這個元素,如果為none,則不顯示,也不參與計算

markDirty

標(biāo)記元素需要重新計算位置,只對葉子節(jié)點生效。

// 獲取驗證碼 -> 重發(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不會占用剩余的空間。如果多個flex item的flexGrow不為0,則按flexGrow的值按比例進(jìn)行劃分。

flexShrink

flexShrink決定空間不足,怎么縮放

align-items、align-self、align-content、

  • align-item

    屬性需要施加在 flex 容器上,它規(guī)定的是 flex 容器中所有 item 在副軸中的對齊方式

    // flex item在副軸拉伸填滿剩余空間
    layout.alignItems = YGAlignStretch;
    
  • align-self

    屬性則施加在 flex 容器中的 item 上,允許單個項目有與其他項目不一樣的對齊方式,它覆蓋了外部容器規(guī)定的 align-items 屬性,同樣也只規(guī)定在交叉軸上的對齊方式

  • align-content

    對比 align-items 和 align-self 直接移動 item 自身在交叉軸上的基線,align-content 移動的是容器自身的 flex line,并僅對多行的項目起作用

常見問題

  • Pod

    使用pod 'YogaKit'安裝的時候,這個庫包含了一個swift文件,對于純OC的項目,這會報錯。

    可以改成

    pod 'IGListKit','2.1.0'
    pod 'Yoga','1.14.0'
    

    然后將YogaKit的代碼(刪除掉swfit文件后)copy到項目中,這部分不使用cocopods進(jìn)行管理,這樣改動比較小

  • AutoLayout

    YogaKit布局設(shè)置的是view的frame,所以如果對視圖添加約束,視圖最終的大小以約束設(shè)置為準(zhǔn)。

    涉及到其他的視圖時,參與計算的是YogaKit自己計算出來的view.frame,而不是約束設(shè)置的值。

實踐

標(biāo)簽流式布局

- (void)tagLayout {
    NSArray *tags = @[@"投資理財",@"超高收益",@"七日年化收益",@"支付寶",@"微信",@"云閃付",@"花唄"];
    
    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%;" />

更新布局

很多時候,我們的視圖大小是依據(jù)視圖內(nèi)容來決定的,比如按鈕的寬依據(jù)title進(jìn)行調(diào)整,title變了,寬也要變,暫時只找到用markDirty實現(xiàn)的方法。

FlexBox是一套通用的布局協(xié)議,YogaKit實現(xiàn)了這個協(xié)議,iOS端可以使用YogaKit來實現(xiàn)FlexBox布局。FlexBox和UIStackView以及Android的LineLayout有相通的地方,優(yōu)勢在于FlexBox是跨平臺的,功能上也更強一點。

YogaKit依據(jù)你的設(shè)置計算出相關(guān)的view的frame,直接設(shè)置frame,所以和AutoLayout可以混合使用,對同一個view進(jìn)行設(shè)置,以AutoLayout的設(shè)置為準(zhǔn)。

YogaKit是從從上往下進(jìn)行計算的,使用過程中需要保證flex container的frame有值,這樣它的flex item才會計算出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è)置或檢索伸縮盒對象的子元素超出父容器時是否換行

padding & margin

iOS 上 padding 對應(yīng)的是 content inserts,但是 iOS 大部分控件都沒有padding,相信很多人都寫過一個繼承自 UILabel的控件來提供設(shè)置 content inserts 的控件,有了YogaKit,那個類以后用不上了。

padding 指的是自身內(nèi)邊距,margin 指的是外邊距,@"H:|-20-[redView]-20-|",這條VFL里的20就是margin。

display

是否顯示這個元素,如果為none,則不顯示,也不參與計算

markDirty

標(biāo)記元素需要重新計算位置,只對葉子節(jié)點生效。

// 獲取驗證碼 -> 重發(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不會占用剩余的空間。如果多個flex item的flexGrow不為0,則按flexGrow的值按比例進(jìn)行劃分。

flexShrink

flexShrink決定空間不足,怎么縮放

align-items、align-self、align-content、

  • align-item

    屬性需要施加在 flex 容器上,它規(guī)定的是 flex 容器中所有 item 在副軸中的對齊方式

    // flex item在副軸拉伸填滿剩余空間
    layout.alignItems = YGAlignStretch;
    
  • align-self

    屬性則施加在 flex 容器中的 item 上,允許單個項目有與其他項目不一樣的對齊方式,它覆蓋了外部容器規(guī)定的 align-items 屬性,同樣也只規(guī)定在交叉軸上的對齊方式

  • align-content

    對比 align-items 和 align-self 直接移動 item 自身在交叉軸上的基線,align-content 移動的是容器自身的 flex line,并僅對多行的項目起作用

常見問題

  • Pod

    使用pod 'YogaKit'安裝的時候,這個庫包含了一個swift文件,對于純OC的項目,這會報錯。

    可以改成

    pod 'IGListKit','2.1.0'
    pod 'Yoga','1.14.0'
    

    然后將YogaKit的代碼(刪除掉swfit文件后)copy到項目中,這部分不使用cocopods進(jìn)行管理,這樣改動比較小

  • AutoLayout

    YogaKit布局設(shè)置的是view的frame,所以如果對視圖添加約束,視圖最終的大小以約束設(shè)置為準(zhǔn)。

    涉及到其他的視圖時,參與計算的是YogaKit自己計算出來的view.frame,而不是約束設(shè)置的值。

實踐

標(biāo)簽流式布局

- (void)tagLayout {
    NSArray *tags = @[@"投資理財",@"超高收益",@"七日年化收益",@"支付寶",@"微信",@"云閃付",@"花唄"];
    
    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];
}
截圖

更新布局

很多時候,我們的視圖大小是依據(jù)視圖內(nèi)容來決定的,比如按鈕的寬依據(jù)title進(jìn)行調(diào)整,title變了,寬也要變,暫時只找到用markDirty實現(xiàn)的方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容