Yogakit介绍

2018-06-12

YogaKit

介绍

YogaKit是Facebook开源的一个CSS3/Flexbox跨平台布局引擎。

iOS原生布局简要说明

iOS中有2种原生布局方式+2种自动布局利器

布局方式名称 说明
绝对布局 声明该元素在父视图中绝对位置
相对布局 声明该元素相对父视图或其他元素相对位置
自动布局名称 说明
autoresizing 标记自己在父视图中的位置、以及相对父视图缩放时是否按比例缩放
autolayout 标记自己相对于父视图或同级其他元素的位置、大小

autoresizing

autoresizing提供了7个布局枚举值,可以组合使用它们完成简单的自动布局。

枚举值 说明
UIViewAutoresizingNone 不会随父视图的改变而改变
UIViewAutoresizingFlexibleLeftMargin 自动调整view与父视图左边距,以保证右边距不变
UIViewAutoresizingFlexibleWidth 自动调整view的宽度,保证左边距和右边距不变
UIViewAutoresizingFlexibleRightMargin 自动调整view与父视图右边距,以保证左边距不变
UIViewAutoresizingFlexibleTopMargin 自动调整view与父视图上边距,以保证下边距不变
UIViewAutoresizingFlexibleHeight 自动调整view的高度,以保证上边距和下边距不变
UIViewAutoresizingFlexibleBottomMargin 自动调整view与父视图的下边距,以保证上边距不变

autoresizing自动布局方案的缺点很明显,它只能做简单的自动布局适配,当视觉需求复杂时,代码中将会出现大量的if else判断语句。

autolayout

autolayout是Apple在iOS6种推出的自动布局方案,给每一个UI元素都添加一套相对于父元素或同级其他元素位置、大小的约束,按照这些约束将UI元素渲染在不同分辨率下,呈现的排版是一样的。

Apple起初的想法是好的,因为这样强约束的布局方案可以有效减少UI嵌套层级,在早年硬件设备性能不是那么好的时候,这种布局方案发挥了极大的作用,但随着硬件性能不断提升,这种布局方案在性能上的优势越来越不明显。

autolayout最大的问题在于程序员需要精确的知道每一个UI元素的约束关系,当页面约束很复杂的时候,对程序员的细心和耐心是极大的考验。然而这根本不算是最严重的问题,一般页面都由若干个组件拼装而成,autolayout最可怕的是不支持热插拔组件,即不可以销毁一个有其他组件依赖该组件约束的组件,程序员如果想要“删除”一个组件,需要添加一个引用指向该组件的宽或高,当需要“删除”时,将该变量设为0,你以为就这么简单的完了?如果再将该组件“插入”回原处呢?

Flexbox解决了什么?

  • 方向性 (传统布局方向是从左到右,从上至下)
  • 弹性伸缩 (传统尺寸定义是通过像素等来精确定义)
  • 元素对齐(可以做到插拔)

从上述几点看来,它似乎完美的解决了iOS原生布局开发效率低的问题,但它会增加页面的嵌套层级关系,在硬件性能饱和的情况下用空间换取开发效率。

Flexbox基本概念

如果元素采用Flex进行布局,那么这个元素就可以称为Flex容器(Flex container),元素的所有子元素称为Flex项目(Flex item)。

下图为Flexbox模型图:
Alt text

几个术语

  • main axis:水平主轴
  • main-start:主轴开始位置,与边框的交叉点
  • main-end:主轴的结束位置
  • cross axis:垂直交叉轴
  • cross-start:交叉轴的开始位置
  • cross-end:交叉轴的结束位置
  • main size:单个项目占据的主轴空间
  • cross size:单个项目占据的交叉轴空间

在iOS端使用YogaKit布局

将一个View开启yoga布局

1
2
3
[view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = YES;
}];

flexDirection

在yoga中,API将所有Flexbox样式属性中的中划线去掉,例如flex-direction改为flexDirection。

flexDirection属性决定主轴的方向(即item的排列方向)。

名称 yoga枚举名 说明
column YGFlexDirectionColumn UIView默认值,主轴为垂直方向
columnReverse YGFlexDirectionColumnReverse 主轴为垂直方向,起点在底部
row YGFlexDirectionRow 主轴为水平方向
rowReverse YGFlexDirectionRowReverse 主轴为水平方向,起点在右端

Alt text
主轴为水平方向,起点在左端

Alt text
主轴为水平方向,起点在右端

Alt text
主轴为垂直方向,起点在上端

Alt text
主轴为垂直方向,起点在下端

flexWrap

flexWrap属性决定内容在抽线上排列不下的换行方式。

名称 yoga枚举名 说明
nowrap YGWrapNoWrap
wrap YGWrapWrap
wrapReverse YGWrapWrapReverse

父容器按行排列

1
2
3
4
[view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = YES;
layout.direction = YGFlexDirectionRow;
}];

Alt text
nowrap不换行

Alt text
wrap换行

Alt text
wrapReverse,起点在主轴底部

justifyContent

justifyContent属性定义项目在主轴上的对齐方式。

名称 yoga枚举名 说明
start YGJustifyFlexStart 左对齐
center YGJustifyCenter 居中
end YGJustifyFlexEnd 右对齐
spaceBetween YGJustifySpaceBetween 两端对齐,item之间的间隔相等
spaceAround YGJustifySpaceAround 每个item两侧的间隔相等
spaceEvenly YGJustifySpaceEvenly 左右边距和每个item之间的间隔一致

父容器按行排列

1
2
3
4
[view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = YES;
layout.direction = YGFlexDirectionRow;
}];

Alt text
start,左对齐

Alt text
center,居中

Alt text
end,右对齐

Alt text
spaceBetween,两端对齐,item之间的间隔相等

Alt text
spaceAround,每个item两侧的间隔相等

Alt text
spaceEvenly,左右边距和每个item之间的间隔一致

alignItems

align-items属性定义项目在交叉轴上的对齐方式。

名称 yoga枚举名 说明
flexStart YGAlignFlexStart 交叉轴的起点对齐
flexEnd YGAlignFlexEnd 交叉轴的终点对齐
center YGAlignCenter 交叉轴的中点对齐
baseline YGAlignBaseline 项目的第一行文字的基线对齐
stretch YGAlignStretch 如果项目未设置高度或设为auto,将占满整个容器的高度

父容器按行排列

1
2
3
4
[view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = YES;
layout.direction = YGFlexDirectionRow;
}];

Alt text
flexStart,交叉轴的起点对齐

Alt text
flexEnd,交叉轴的终点对齐

Alt text
center,交叉轴的中点对齐

Alt text
baseline,项目的第一行文字的基线对齐

Alt text
stretch,如果项目未设置高度或设为auto,将占满整个容器的高度

alignContent

align-content定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

名称 yoga枚举名 说明
flexStart YGAlignFlexStart 与交叉轴的起点对齐
flexEnd YGAlignFlexEnd 与交叉轴的终点对齐
center YGAlignCenter 与交叉轴的中点对齐
spaceBetween YGJustifySpaceBetween 与交叉轴两端对齐,轴线之间的间隔平均分布
spaceAround YGJustifySpaceAround 每根轴线两侧的间隔都相等
stretch YGAlignStretch 轴线占满整个交叉轴

父容器按行排列

1
2
3
4
[view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = YES;
layout.direction = YGFlexDirectionRow;
}];

Alt text
flexStart,与交叉轴的起点对齐

Alt text
flexEnd,与交叉轴的终点对齐

Alt text
center,与交叉轴的中点对齐

Alt text
spaceBetween,与交叉轴两端对齐,轴线之间的间隔平均分布

Alt text
spaceAround,每根轴线两侧的间隔都相等

Alt text
stretch,轴线占满整个交叉轴

flexGrow

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

父容器按行排列

1
2
3
4
[view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = YES;
layout.direction = YGFlexDirectionRow;
}];

Alt text
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍

flexShrink

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

父容器按行排列

1
2
3
4
[view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = YES;
layout.direction = YGFlexDirectionRow;
}];

Alt text
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
负值对该属性无效。

alignSelf

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

flexBasis

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。