flexBox布局之yogakit

flexBox布局之yogakit

本次分享目的:

介绍一种有别于frame手算布局的布局框架,更快速,大大提升产生力

背景:

  • 多终端,多尺寸设备的现状使得UI布局越来越重要

随着这几年前端技术的崛起,前端UI布局系统也在其中占据了越来越重要的位置。不管是在移动端、桌面端还是Web端,特别是不同设备的屏幕大小和分辨率千变万化,如何构建良好的布局系统得越来越重要。

  • 现状:各平台各自布局方案,维护成本高,无法共享

目前的情况是各个平台都有自己的一套解决方案。iOS平台有自动布局系统,Android有容器布局系统,而Web端有基于CSS的布局系统。多种布局系统共存所带来的弊端是很明显的,平台间的共享变得很困难,而每个平台都需要专人来开发维护,增加了开发成本。

  • React Native中实现了一种跨平台的基于CSS的布局系统

React Native里引入了一种跨平台的基于CSS的布局系统,它实现了Flexbox规范。是他的一个子集

  • 不断完善发展后形成了一款跨平台的布局引擎:Yoga

随着这个系统的不断完善,Facebook对它进行重启发布,并借助Yoga,不仅可以在React Native里,还能在各个平台上快速地构建UI布局。

Yoga简单介绍:

Yoga是基于C实现的。基于C实现的Yoga比之前Java实现在性能上提升了33%。使用C实现可以更容易地跟其它平台集成。到目前为止,Yoga已经有以下几个平台的绑定:Java(Android)、Objective-C(UIKit)、C#(.NET)。而且已经有很多项目在使用Yoga,比如React Native、Components for Android、weex, luaView等等。

不同于其它的一些布局框架,比如Masonry,它们要么不够强大,要么不支持跨平台。Yoga遵循了Flexbox规范,同时又将布局元素抽象,为各个不同平台暴露出一组标准的接口,这样不同的平台只需实现这些接口就可以了。

Facebook把Yoga开源了,除了完全遵循Flexbox规范,在未来为Yoga加入更多特性,这些特性将超出Flexbox的范畴。

Yoga官方网站:https://facebook.github.io/yoga/

Flexbox布局概念:

Flexbox布局( Flexible Box 或CSS3 弹性布局),是CSS3中的一种新的布局模式。使用Flexbox来布局更容易,可以使用更少的代码,更简单的方式实现更复杂的布局,例如对齐方式,排列方向,排列顺序(这也是Flexbox布局的核心能力所在),弹性盒中的子元素通过在各个方向放置就可以以弹性的尺寸适应父元素的显示区域。独立显示被设定成只针对可见元素,而不是基于代码的声明和导航顺序。

image

Flexbox布局教学:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

YogaKit使用:

iOS 中使用 YogaKit,它是 C 实现的一个封装。

YogaKit 将 YGLayout 暴露作为 UIView 的一个分类。这个分类在 UIView 中增加了一个 configureLayout(block:) 方法。block 闭包带一个 YGLayout 参数,你可以用这些数据来配置 view的布局属性。

一些基本的布局属性:

justifyContent : item项目 在容器主轴方向上的对齐

flexdirection:决定主轴的方向(即 item的排列方向)。

padding : 添加一个内白

marginXXX: 增加一个边距

width:宽

hight:高

alignItems:item项目在交叉轴上如何对齐

alignSelf:容器自身的对齐位置

通过将每个子 view 配置所需的 Yoga 属性来构建布局。然后,调用根 view 上的 YGLayout 的 applyLayout(preservingOrigin:) 方法。然后布局会被计算并应用到根 view 和 subview 上。

源码文件:

image
  • 其中yogakit目录下是oc是接口
  • 核心文件在yoga.m中
  • 相比较masonry很轻量级
  • 可以和frame布局一起使用

demo:

  • 免去计算滚动视图的高度,

  • 免去计算tableview的高度;

YogaKit布局源码解析:

oc布局执行入口:

- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin

执行下面方法:

- (CGSize)calculateLayoutWithSize:(CGSize)size

要求布局必须在主线程。

然后节点布局计算:

 void YGNodeCalculateLayout(const YGNodeRef node,
                            const float parentWidth,
                            const float parentHeight,
                            const YGDirection parentDirection) 

这是一个包装YGNodelayoutImpl函数。它决定了布局请求是否冗余,可以跳过。输入参数是一样的YGNodelayoutImpl返回参数是true的:

bool YGLayoutNodeInternal(const YGNodeRef node,
                      const float availableWidth,
                      const float availableHeight,
                      const YGDirection parentDirection,
                      const YGMeasureMode widthMeasureMode,
                      const YGMeasureMode heightMeasureMode,
                      const float parentWidth,
                      const float parentHeight,
                      const bool performLayout,
                      const char *reason,
                      const YGConfigRef config)

最后布局算法实现:
static void YGNodelayoutImpl(const YGNodeRef node,
const float availableWidth,
const float availableHeight,
const YGDirection parentDirection,
const YGMeasureMode widthMeasureMode,
const YGMeasureMode heightMeasureMode,
const float parentWidth,
const float parentHeight,
const bool performLayout,
const YGConfigRef config)

性能比较:

image

上图是3个布局算法在嵌套情况下的性能比较图。FlexBox的性能接近于原生的Frame。而嵌套情况下的Autolayout的性能很差;

布局算法主要步骤:

  1. 对特殊节点和情况进行预处理:
    • 内容节点:采用 measure 方法,通过回调视图对文本实际计算得到的尺寸确定宽高
    • 叶子节点:没有子视图的,直接求解,不进行递归计算
    • 对不需要计算布局的节点直接求解
  2. 确定节点内每个子节点的 flexBasis
  3. 对节点内所有子节点遍历,对元素分行并计算主轴和交叉轴对齐:
    • 将子节点分行
    • 计算当前行内元素在主轴上的尺寸,计算当前行剩余可分配空间
    • 计算当前行内元素在主轴上的位置,计算当前行内元素在交叉轴上的尺寸
    • 计算当前行内元素在交叉轴上的位置
  4. 计算节点的多行对齐,更新元素在交叉轴上的位置
  5. 计算节点的最终尺寸和位置
  6. 计算绝对定位子节点的尺寸和位置
  7. 设置子节点的 trailing 位置

预处理:

内容节点:

LabelTextField 等文本节点和 ImageView 等由内容决定的节点直接通过外部传入的 measure 回调拿到尺寸。

measure 方法可以通过协议让具体的视图来实现。

叶子节点

对没有孩子的叶子节点,由于不需要递归计算内部子节点的布局,因此可以直接通过指定的模式算出估计尺寸,跳过接下来的流程。

非布局节点

同样,在对布局树的多次递归过程中,对于只需知道子节点尺寸而不需要知道位置的情况,会把 performLayout 标志位置为 NO 来跳过计算量消耗较大的计算位置的流程。

确定 flexBasis

这一步确定容器中每个子元素的在主轴上的 flexBasis 值。flexBasis 是每个元素的在未扩展和压缩前的基准尺寸,父容器用来计算主轴的剩余空间,然后根据扩展和压缩比例系数为每个 Flex 子元素调整尺寸。由于绝对定位子节点不参与 Flex 布局,因此不需要计算 flexBasis 值,在这一步中,会先把绝对定位子节点存储在链表中,在 Flex 布局完成后再单独计算所有绝对定位节点的布局。

缓存机制

CSSLayout 算法中的缓存分为两个层次,即把渲染树中所有节点的布局结果和估计结果都缓存起来,只有当两棵渲染树计算条件完全匹配时才会触发;另一种复用要求较低的,只把中间的估算结果缓存起来,内部缓存最近 16 次的计算结果, 在渲染树增量更新、插入节点等部分更新情况下避免重复估算尺寸,但对节点的布局仍需计算。

相关参考资料:

https://facebook.github.io/yoga/

https://juejin.im/entry/59924874518825485e1d5129

https://zhuanlan.zhihu.com/p/26856290

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355

推荐阅读更多精彩内容

  • FlexBox - YogaKit FlexBox是一套通用的布局协议,YogaKit实现了这个协议,iOS端可以...
    观星阅读 2,773评论 0 0
  • 前段时间接手了一个基于cef1的项目,由于其特别限定的场景,在查询了对html5的支持后,整站都采用了flexbo...
    JSoon阅读 11,902评论 1 10
  • 简书的Markdown貌似不支持插入iframe,所以文章里的JSFiddle示例都改做截图了,如果有需要可以点击...
    kangflict阅读 1,123评论 2 8
  • Texture快速开始(C) 1.1: Motivation & Benefits 对于复杂的视图层次结构来说,U...
    iYeso阅读 1,495评论 0 3
  • Yoga 主体部分翻译自 https://facebook.github.io/yoga/docs 部分参考 阮一...
    songkl阅读 5,083评论 1 8