此前,前端工程师考试测验过将业务组件模块化构建成通用视图库,并通过拖拽、拼接等形式搭建业务模块,从而实现视图复用,降落设计稿转代码的研发本钱。
但随着业务的发展和个性化的驱动,通用视图库无法覆盖所有运用处景,本文提出了一种设计稿自动天生代码的方案。

1 背景

设计稿(UI视图)转代码是前端工程师日常不断重复的事情,这部分事情繁芜度较低但事情占比较高,以是提升设计稿转代码的效率一贯是前端工程师追求的方向之一。
此前,前端工程师考试测验过将业务组件模块化构建成通用视图库,并通过拖拽、拼接等形式搭建业务模块,从而实现视图复用,降落设计稿转代码的研发本钱。
但随着业务的发展和个性化的驱动,通用视图库无法覆盖所有运用处景,本文提出了一种设计稿自动天生代码的方案。

目前,业内主流的代码天生方案有两种,一种是通过演习神经网络,从图片或草图直接天生代码,以微软sketch2json为代表;另一种是基于Sketch源文件,从中解析出图层信息转化成DSL并天生代码,以imgCook为代表。
经由实践,我们创造第一种方案基于神经网络的代码天生算法虽然大略粗暴,但繁芜层布局的准确率较低、可阐明程度不高导致后续无法持续优化。
方案二中Sketch源文件信息量丰富、算法自定义程度高、优化空间大。
因此,我们调研了业界基于Sketch的代码自动天生方案(已对外公布或者开源),创造了一些不敷并考试测验办理,下面从算法准确率、代码可读性、研发流程覆盖度等方面做一下比拟(该比拟结果仅稽核业界方案对我们自己业务的适用性,实际结果可能存在差异):

设计稿UI视图自动生成代码筹划的探索

算法准确率方面:淘宝imgCook支持基于AI的组件识别,不支持成组布局,准确率中等(从官网理解到可以识别循环布局,但不能识别出测试样本中的循环布局),58 Picasso仅支持原始组件的识别,繁芜组件天生缺点较多,不支持成组/悬浮/循环布局,准确率较低。
代码可读性方面:淘宝imgCook在天生布局时,测试样本中图层重叠区域利用到了基于根布局的绝对定位办法,不符合RD预期,可读性一样平常,而我们的方案利用相对定位办法,可读性较好。
研发流程覆盖度方面:淘宝imgCook从RD视角构建了一个IDE,支持在IDE中完成样式调度、逻辑绑定;而我们的方案从产研协作视角出发,支持数据、逻辑、埋点的可视化配置及上线。
2 方案先容

如图所示,配置平台紧张分成三块包括:设计稿转视图树(UI2DSL)、视图树转代码(DSL2Code)、以及业务信息绑定,下面大略先容一下每一块的浸染。

设计稿转DSL视图树(UI2DSL):将设计稿转化成平台无关的DSL视图树。
视图树转代码(DSL2Code):将DSL视图树转化成基于Flex布局的MTFlexBox静态代码。
业务信息绑定:供应可视化配置工具,支持MTFlexBox静态代码绑定后台数据、业务逻辑、以及曝光/点击等埋点逻辑。
2.1 设计稿转视图树(UI2DSL)

UI2DSL紧张经历以下四个步骤:

2.1.1 设计稿导入

在日常开拓过程中,我们打仗比较多的组件有按钮、标题、进度条、评分组件等,但是Sketch数据源中并没有这些组件只有图层信息,图层是设计师在设计UI视图时用到的视图控件。
组件与图层的对应关系是一对多的关系,图层在Sketch数据源中的表现形式如下图中的JSON数据构造所示,描述了图层的坐标、大小等信息,后续布局生造诣是基于对图层的切割来实现的。

[{"class_name":"MSTextLayer","font_face":"PingFangSC-Medium","font_size":13.44,"height":36.5,"index":8,"line_height":18.24,"name":"恒都民生精选猪小排带骨400g±25g","object_id":"EF55F482-A690-4EC2-8A6E-6E7D2C6A9D91","opacity":0.9000000357627869,"text":"恒都民生精选猪小排带骨400g±25g","text_align":"left","text_color":"#FF000000","type":"text","width":171.8,"x":164.2,"y":726.7},//......]2.1.2 组件识别

从上面的数据源可以看出,图层有图片、笔墨、矩形等基本类型,在组件识别这一步图层须要被转化成笔墨/图片/进度条/评分组件/价格组件/角标等日常开拓利用的组件类型。
但是目前我们的进展还勾留在只能将图层识别为笔墨或者图片的阶段,后续我们将接入淘宝开源的pipcook框架,基于神经网络算法进行更加丰富的组件类型识别。

2.1.3 可视化干预

设计稿作为输入源是设计稿自动转代码的根本,这对设计稿的设计规范哀求较高。
但在实践中,我们创造设计师会利用Sketch中的基本图形(每个图形终极形成数据源中的一个图层)叠加来描述一个组件的视觉效果,因此设计稿中不可避免会涌现冗余图层的问题,滋扰DSL的天生。
虽然我们也考试测验了利用自动化的手段删除冗余图层,但对付算法不能识别的部分(例如:图片上有一个文本图层,但是实际情形中文本是显示在图片里的,这个时候无法从算法层面决定是否删除文本),仍旧须要靠人工进行图层删除、合并等,否则无法正常天生DSL。
设计稿紧张有以下几类问题。

图层未合并

上图是从设计稿解析出来的结果,可以创造在“美团优选”笔墨上方的图片中有很多赤色的矩形框(每个矩形框是一个单独的图层),而算法预期的输入是一个图层,因此须要在算法处理前将多个图层合并成一个图层,右侧的三张图也有类似问题。
我们与设计同学进行过沟通,设计同学表示乐意在产出设计稿之前将图层进行合并,但由于目前无法供应检测机制(图层合并是否有遗漏无法自动检测出来),也就无法彻底避免图层未合并的问题。

图层位置交叉

实践中创造当设计稿中不同字体/大小/颜色的笔墨排列在一起时,解析出来的图层信息每每会涌现重叠的情形,由于DSL视图树算法依赖位置来确定不同组件的约束关系,因此位置的交叉会对算法准确度造成较大的影响。

繁芜背景图层

上图中赤色背景是由2个图层(2个蓝色矩形框)拼接形成的,左图上的蓝色图层是纯色,右图上的蓝色图层是渐变色,在两个图层未合并的情形下,算法天生的代码将会出错。

上面提出的问题,通过约束设计师来达到设计稿的规范化,难度较大,以是我们供应了可视化干预工具。
下面对上述问题做一个大略的总结:

问题一:图层未合并问题肉眼很随意马虎识别出来,利用工具将冗余图层进行快速合并删除即可。
问题二:图层交叉问题肉眼不易识别,因此我们供应了检测工具,基于检测工具可以对设计稿中的交叉问题快速修复。
问题三:繁芜背景问题肉眼不易识别,暂时也没有有效的检测工具,用户可以采取边干预边天生的办法天生DSL。

可视化干预是UI2DSL主要的一环,经由可视化干预,将不标准的设计稿转化为标准的图层信息后再输入给算法,可以极大地提升算法的准确率。
这里我们和imgCook的处理办法有一个差异:imgCook在引入了阈值处理等算法后(更智能,出错概率更大),可视化干预能力紧张表示在事后,而我们在天生DSL之前许可用户对图层进行干预,在干预时用户面对的是直不雅观的图层信息,可以有效降落工具的利用门槛(更稳定,效果更好)。

2.1.4 视图树天生

将扁平的数据源转化为树状构造的DSL,这个过程如果是人脑来做会怎么思考呢?先确定布局的整体构造是行布局或者列布局,然后再确定局部区域该当是什么布局构造,末了组装起来形成视图树。
这个过程与递归算法类似,因此我们采取了递归算法作为算法的主框架,同时引入了“横竖切割+布局构造+模型评估”三大利器。

利器一:横竖切割

天生DSL时采取了整分的思路,即将大布局不断的切分成小布局,下面以动画的形式看一下简化过的DSL天生过程:

将设计稿一部分区域视为一个子区域,最开始的时候子区域和全体模板的面积一样大,基于图层的位置、大小信息,打算每个图层的上/下/左/右边缘坐标与其他图层的相对关系,就可以探求到切割点(如上图中赤色箭头所指的位置)。
接下来依据切割点,将子区域切割成更小的子区域,在切割的过程中如果切割点是横向的,则天生列布局;如果切割点是纵向的,则天生行布局。
通过不断的切割子区域得到更小的子区域,直到所有的子区域只剩下图片或者文本等不可切割的图层,这样就可以天生完全的DSL视图树了。
为了方便读者理解,图例中只演示了行布局、列布局的切分过程,实际情形还包含了其他布局类型,会要繁芜许多。

这里还要把稳一个问题,当有3个切割点时,我们选择了直接将子区域切割成4个子区域,实际上我们可以只选择1个切割点进行切割,也可以选择2个切割点进行切割,当有N个切割点时,实际上存在(N的阶乘+1)种切割办法,详细选择哪种切割办法,我们会在利器三中谈论。

利器二:布局构造

每个图层都是一个矩形,为了天生布局构造只能依赖矩形的高下旁边坐标信息。
因此,对布局构造进行分类时,我们根据矩形与矩形之间的位置关系(相交、相离和包含关系)做了以下分类。

把稳:从天生DSL的结果来看,包含布局和成组布局的处理办法实在是一样的,都是利用类似于FrameLayout的层叠布局包含内部图层元素,但是我们仍旧保持分类原则(矩形之间的位置关系)不变。

上图中,相离、包含比较好理解,为什么两个图层相交的时候,会有成组和悬浮两种类型的布局构造呢?我们看下上述成组布局、悬浮布局两个设计稿等分别标出了相交的元素A、B,它们在位置上的相对关系是一样的,都是A、B两个图层对应的矩形框发生了交叉。
但是我们希望空想态的DSL视图树却有所差异,如下图所示:

成组布局中:A、B逻辑上是一个整体,交叉是一定的,终极DSL中A、B被层叠布局包含,层叠布局中没有其他元素。
悬浮布局中:A、B逻辑上不是整体,只是恰巧交叉了,终极DSL中A、B分别在不同的层级中。

因此,对付图层相交时可能有两种类型的布局构造,分别是成组布局和悬浮布局。
从上图可以看出利用成组布局还是悬浮布局是由图层内容决定的,那么就须要算法理解图层内容了,比如基于AI构建样本库,记住所有的角标样式(上面表格中4描述的),下次碰着角标相交时就天生成组布局。
考虑到AI模型也是对规则的抽象,我们先搭建一套自定义识别规则。
成组布局其位置信息是有规律可循的,例如:角标常常涌如今右上角,标签常常涌如今左上角,头像常常横向或者纵向交叉等,因此我们针对图层之间的位置关系构建了交叉模型,如下图所示:

上图的交叉模型可以记住历史模板中成组布局图层之间的位置关系,下次碰着相交布局时判断是否在历史规则库中即可完成识别,如果在就按成组布局处理否则按照悬浮布局处理。
下图是通过历史模板构建的成组规则库。

上面先容了本方案中涉及的5种布局类型,目前来看这五种布局类型可以描述所有的模板布局,并且天生代码符合RD的预期。
下面展示两个设计稿DSL实例:

利器三:模型评估

在先容横竖切割时,可以看到当存在多个切割点时,对所有切割点同时进行了切割,但实际上算法在切割时繁芜度会更高,当有三个切割点时,实际上有5种切割办法,每种切割办法都会天生一个DSL。
既然有5种切割办法,那么到底该当选择哪一种DSL呢?模型评估算法便是用来办理这个问题的。

目前模型评估算法有两个指标:布局节点数和逆布局指数。

DSL中布局节点数越少,切割办法越好。
逆布局指数用来评估DSL中的行列布局的合理程度,个中逆布局指数越大越不合理,反之,逆布局指数越小,切割办法越好。

以下图为例,看下视图不同切割办法下对应的模型评估办法:

如果模型评估算法只衡量布局节点数的话,那么会选择第一种切割办法天生的DSL作为终极的结果。
但实际上,第二种切割办法更加合理。
在切割办法一中,广告、立即预约处于一个列布局中,但是横向对齐办法(交叉轴)却不一样,“广告”是右对齐,“立即预约”是左对齐,逆布局指数表示交叉轴对齐办法不一致的节点数量,因此通过逆布局指数,我们可以规避掉不合理的切割办法。

2.1.5 列表布局

上一节先容了基本的布局构造,虽然说这些布局构造已经可以描述所有的UI布局,但是与RD的编码习气还是有一些差异。

对付上面的布局,RD常日不会把相同的item写五遍,而是会将item放在一个类似于ListView的列表组件中,使代码看起来简洁易懂。
因此在DSL天生阶段,除了识别基本的行/列/包含/成组/悬浮布局外,还须要进一步识别行/列布局中的元素是否形成列表布局。
在试验过程中,我们创造列表布局分为两种:单状态列表组件和多状态列表组件。
上图中每一个item的布局构造都是一样的,我们称为单状态列表组件,再来看一下多状态列表组件(如下图所示),每个item有多种状态(选中态和非选中态),并且不同状态的布局构造不一致。

对行/列布局中单状态列表组件的识别,只须要比较item子视图树的构造,子视图树构造同等则判断为单状态列表组件。
对多状态列表组件的识别我们采纳了自动识别+人工干预的办法,自动识别的办法比较粗暴,只要行列布局中子item的宽/高靠近,并且子item不是基本组件(基本组件随意马虎形成误判),就剖断为多状态列表组件。
详细算法是打算子item宽高的标准差,小于阈值就剖断为多状态列表组件,否则不是。
公式如下:

那为什么还要人工干预呢?由于是否利用列表组件实在与产品逻辑干系,但是目前我们无法将产品文档中的逻辑识别出来,只能尽可能识别出所有的多状态列表组件,并许可用户对天生结果进行变更。
比如上述送恋人的设计稿,产品可能约定每一个item都有选中态/非选中态两种状态,也可能是从业务角度考虑须要着重突出送恋人这个item,这时每个item就只有一种确定的状态,这两种不同的产品逻辑在编写代码时有不同的最优技能方案。

2.2 视图树转代码(DSL2Code)

DSL视图树只是天生代码的中间产物,还须要对DSL进行代码还原,DSL2Code紧张包括两个步骤:属性推断、属性信息调度。

2.2.1 属性推断

属性推断包括两个部分:样式属性和构造属性。
样式属性包括字体、背景色、圆角等可以直接通过数据源信息中获取得到的属性;构造属性包括大小、内外边距、主辅轴对齐等构造信息,这些信息无法从数据源中直接获取,以是构造信息的推断是这部分事情的重点。

构造信息推断算法同样利用递归算法作为主框架,通过一次递归对所有元素进行两次遍历来完成构造信息的推断。
如下图所示,在对DSL所有节点进行递归遍历时,把所有元素依次加入行列步队中,递归完成后,再把所有节点依次移出行列步队,这样一进一出便对所有元素完成了两次遍历,我们把这两次遍历称为进队遍历和出队遍历。

进队遍历时,推断算法根据数据源中信息记录每个节点的大小和位置信息,并根据位置关系打算每个子节点在父节点中期望的主辅轴对齐办法和内外边距。
出队遍历时,父节点会根据子节点期望的对齐办法确定父节点终极的主辅轴对齐办法,并根据子节点的拉伸意图改动父节点的大小。
拉伸意图即节点的大小不固定,根据显示内容不同,在水平或垂直方向上可能会变大或变小,例如文本节点根据显示字数的多少长度会发生变革,字数过多时乃至还会换行。

2.2.2 属性信息调度

由于输入源是基于设计稿呈现的静态效果图,设计稿中每个元素缺失落了真实的业务含义,同样的展示效果在不同的业务场景中会有不同的属性哀求,对付这部分内容,我们无法从输入源中进行准确推断。
为此,我们供应了可视化的属性信息调度功能来赞助代码天生,页面效果如下图所示,在这个页面可以对DSL中的所有节点属性进行查看和修正调度。

经由业务信息补充后,便可进行末了的自动代码转化,通过语法映射自动把DSL转化成MTFlexbox模板代码。

3 成果展示

下面是设计稿直接天生代码未经修正展示后的手机屏幕截图,可以看到取得了不错的还原效果:

以上便是我们近期对代码自动天生的探索及实践,后续我们将引入机器学习及神经网络算法,对过程进行进一步优化。
如果您有其他的意见或建议,也欢迎在文末进行评论,或者跟我们联系。

作者简介

田贝、少宽、腾飞等,美团平台终端业务研发团队研发工程师。

团队简介

美团平台终端业务研发团队的职责是保障平台业务高效、稳定迭代的同时,持续优化用户体验和研发效率。
团队卖力的业务紧张包括美团首页等千万级DAU高频业务以及分享、账号、音/视频等根本业务,支撑和对接外卖、酒店等30多个业务方。
团队通过动态化能力培植,加快业务上线速率,帮助产品(PM)快速验证业务选型,做出业务决策;架构/做事标准化体系培植,提升前后端以及平台与业务线的沟通、互助效率;业务监控和体验优化,有效保障核心业务做事成功率的同时,提升用户利用美团App过程中的稳定性和流畅性。
团队开拓技能栈包括Android、iOS、React Native、Flexbox等。

招聘信息

美团平台终端业务研发团队是一个活力四射、对技能充满激情的团队,现诚聘Android、iOS、FE工程师,欢迎有兴趣的同学投简历至tech@meituan.com(备注:美团平台终端业务研发团队)。

--

本文系美团技能团队出品,著作权归属美团。
欢迎出于分享和互换等非商业目的转载或利用本文内容,敬请注明“内容转载自美团技能团队”。
本文未经容许,不得进行商业性转载或者利用。
任何商用行为,请发送邮件至tech@meituan.com申请授权。