百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

UI2Code智能生成Flutter代码——机器生成代码

toyiye 2024-06-06 22:12 13 浏览 0 评论

背景

在《UI2CODE--整体设计》篇中,我们提到UI2Code工程的整体流程。前步图片分析之后,我们可以得到对应的DSL布局描述。利用DSL的资讯,结合IntelliJ Plugin介面工具,面向使用者提供生成对应Flutter代码。

本篇主要介绍我们如何处理DSL的资讯,想法上即是Flutter的翻译机。总体概念如下:

输入的DSL是什么?

DSL做为一种描述语言,抽象表示为了解决某一类任务而专门设计的计算机语言。在此我们的DSL代表图像识别和布局识别侧的输出,为一JSON格式。

这些资讯主要描述了这个图层(Layer)的范围(Frame)、是什么样子的类型(Type)、是什么样子的样式(Styles)、含有哪些数据(Value)等等。图层集(Layers)栏位则代表了这张视觉稿的所有图层。

核心思路

本节的目标是将DSL翻译成目标的Flutter代码。我们首先需要理解的是分散的图层间的关系,可能会有交叠、可能是并列排版。知道了关系之后,需想办法转化成Flutter widget的视图,根据此视图来生产对应代码。

架构上我们把DSL tree和Flutter tree的建立,分拆为两个独立的分界。这样比较容易定义问题,并且保持弹性。如果今天的目标语言换成Weex或是iOS UI,我们就只需要更动代码翻译的模组。

第一把刀:DSL tree建立

上图的左侧代表了来源DSL的layers资料,代表者一个一个的图层。右侧是目标的DSL Tree,这棵树的结构上明确叙述了图层之间的包裹、交叠等关系。并且包含了某些特殊关系的节点聚合。

作法上利用每个Layer的Frame,以及所属的类别(文字、图像、容器),利用下面的规则组合树的关系:

  1. 图层之间的包裹关系,例如某些图层为容器,代表下面是可以挂其他节点的(这边带有背景属性的容器,我们定义称之为Shape)
  2. 区块式组件(Block, 如ListView/GridView)。可以将图层组成View item的关系
  3. 闲鱼定义的组件资讯(如CI以及BI),这部份非闲鱼工程可以忽略
  4. 重复布局(Repeat)的资讯,将相同的图层归类合并,目的为简化树

根据以上我们采用了分层,由大至小的次序将Layer分群合并。另外,在合并时layer之间彼此可能有关联;它们可能同属于Block,也可能同属于某个Repeat。所以对于上面定义的Repeat、BI、Block、CI、Shape都可能有交错的嵌套关系,这是必须要处理的部份

第二把刀:Flutter tree建立

在Flutter Tree的建构中,核心概念先处理布局。布局的概念如剥洋葱一般,我们先去除四周的padding,然后以人类视觉layout的直觉先尝试横切分,再进行竖切分。

1.先剥洋葱去除padding

2.接著我们的算法会先尝试是否可以横切,如下图我们可以切割成为Row1/ Row2

3.针对Row1在尝试再进行竖切,如下图可以得到Column1/ Column2/ Column3

根据以上切分的规则,我们就可以定义出如Row、Column、Padding的几个节点,以及它们的Parent/ Child关系。将DSL tree同一层的节点做切分,一边切分一边建立Flutter node,遍历完整颗DSL,即可得到粗略的Flutter tree关系。

= 无法切分时的处理

当图层切分不开时,这时候就要使用绝对布局叠层的概念,这个概念在Flutter内称之为Stack。

多个图层在DSL tree的关系为兄弟节点,根据此些图层的Frame,我们判断出来它们是彼此相交的,我们会以Z-order概念,来决定上下交叠的关系。最后,这些图层将组成一个新Stack节点,并且产生此节点的Frames为此些图层覆盖的范围。

= 针对文字的进阶处理

基本上交叠的图层以Stack的处理就可以正确显示,但在文字图层上可能含有误区。

如上图因为文字本身的上下左右是含有padding的,在我们图层的识别时,可能会计算出彼此的frame是交叠的,但实际上UI希望它们并不是Stack关系。

为了解决这个问题,我们引入了一个oriFrame的概念,用文字最原始的像素当做是oriFrame。所以遇到为文字的图层时,我们会先判断本身的oriFrame是否交叠,如果是的话才采用Stack切割,否则就以此oriFrame对原始的frame做修正。

文字还有什么特性?

另外,因为文字的内容通常是动态的,所以拥有了”所见不一定为所得”的特性。这些特性主要包含了是否该换行、内容区域是否可以拉伸、文字Padding等,这些特性都会影响到我们的布局。

以下图为例,我们在处理Layout时肉眼很明显可以知道这些特徵。文字的行数我们可以以视觉稿当做最大显示范本,文字区域的宽度部分,则需要特别判断哪些区域是可以被拉伸的。

确立文字范围

在决定拉伸对象之前,我们需要定义哪些widget是将内容完整显示,不能被拉伸的:如图片、Container容器、Stack区域、Component组件

接著处理的流程如下:

  1. 首先判断所有Child内是否有多行文字或宽度固定的文字,如果是的话针对其处理。需要加上Flex。
  2. 若无以上的状况,则判断Child间的Padding关系
  • 如果可拉伸的widget的Padding大于平均值的个数有多个,则这些都加上Flex
  • 如果只有单个时,则找寻最大Padding的widget(使用分群拉伸算法)
  1. 最后,但当Row里面存有拉伸的状况时,需要把Row的最后一个child加上Right padding,否则拉伸元素会填满父容器。

分群拉伸算法:这个算法的目的是找到最佳拉伸的对象。我们的思考上将Widget做分组,分组后判断整体的Alignment(如左右对齐)或是拉伸关系。若在拉伸状况下,判断适合让哪个组别拉伸,在进一步判断适合让组别的内部元件拉伸。

举例如下为一个Row排列的控件,其中排列为Image、CI、Text1、Text2、Text3:

依据Widget之间的距离,在上图分为了Group1及Group2两个群体。先以Group1判断是否存在可拉伸的对象, 接著才判断Group2。所以这5个Widget分别得到了3, 2, 1, 4, 5的优先级。以本例而言,Text1为最高优先,而且其为可拉伸的,故决定将Flex属性加于此。

在Expanded的处理上,是我们目前遇到最大的困难点,甚至人工判断都可能有歧义。上面的规则是我们归纳出众多视觉稿的通解,但不能100%完全解决问题。所以这部份判断错误的部分,我们期待在Plugin的交互中使用人工解决。

= 判断Alignment优化

以上的处理已经可以正确生成Flutter tree,但是我们想进一步地将Flutter代码更加优雅。在此我们针对了三种元件的Alignment做了处理,分别是Container、Row、Column,其概念都是分析内部元件的padding关系,决定为居左、居中、或是居右对齐。

举例如Column内部的children我们去判断左右的padding是否相等。若是则移除其padding,并且加上crossAxisAlignment为center。

针对Row/ Container我们则会判断crossAxisAlignment(垂直方向)以及mainAxisAlignment(水平方向)。水平部份,这边我们采用更精细的方法,我们利用欧式距离建立一个非监督算法,计算views是更为接近哪一个(居左、居中、居右)。算法这边先不详述,之后再以篇幅介绍。

最后:生成Flutter代码

经过前面的步骤后,最终我们产生了一个Flutter Tree。生成时在节点的定义上,我们分为了两种,分别是View与Layout,以是否可以拥有Child为区别。以下是我们针对Flutter Tree所定义的部份类别:

在节点的定义中,皆存储了各节点的Parent、Child属性。根据这些关系,我们定义每个节点的代码样板,例如FColumn对应的样板为:

new Column(
#{alignment},
children: <Widget>[
 #{children},
]

),

最后我们以Root widget开始遍历整颗树,将每个节点所生成的Flutter代码结合,这样我们就可以得到整个Widget tree的代码了。

数据分离

为了更好的重复利用生成代码,我们把生成的代码和数据再进一步做分离。分离后输出分为代码区以及Data model数据区:

我们切割这些区域的目的为简化Widget tree直观上的代码复杂度,以及将数据抽离,让资料可由外部呼叫传入,以达成动态性。

整体架构回顾

总合以上的概念,工程的细部架构如下:

前面所说的针对文字以及Alignment的处理,在这边我们设计了一个工厂模式,如上图中经过Flutter Tree Builder后,我们可以去遍历整颗Widget tree,在工厂中判断判断符合条件的规则,经过处理去震荡优化原本的Widget tree。在这边未来我们可以不断地加上合适的规则,让Widget tree更加优化。

整体架构使用静态分析的方法,读到此各位可能会有疑问:一些如动态的事件、View的Visibility、Input输入文字框等怎么处理?由于这些动态性在静态分析下无法解决,所以我们增强了Plugin上的编辑性,使用者只要勾选某些属性,即会在生成代码时自动判断,在Flutter自动增加对应的逻辑。以弥补静态图无法处理的问题。

由于UI的灵活性高,十个人写的代码可能有十种不同风格。并且在分析上游的UI2DSL,以及Flutter代码的翻译,某些部份的精确性取决于我们的样本的认知,是否能够在有限的样本内观查出泛化的定律,分析上还是存有很多挑战性。

结合落地业务

在整个UI2CODE的效果中,大约七成以上的页面都可以正确分析出来,剩下的是一些小细节如文字的处理等,基本上我们工具都能够将大框架的处理好,使用者可能只需微小的调整。

UI2CODE案子在内部团队上线后,已经在闲鱼APP内的"玩家页面"采用了自动化生成的代码。在采用自动化工具后,大约减少了三分之二的UI开发时间(因初期还在熟悉工作流程,未来相信可以更快速)。同时,若在客户端大量采用我们工具,还可以让团队的代码结构有一些的规范,让生成工具来规范Widget UI以及Data Binding的框架,一致性以及后续的维护,相信是一个很大的诱因。

并且闲鱼团队近期计画开发一款新的APP,在初期时能够快速开发UI,也将采用我们的工具。期望有更多的业务和经验积累。

后续计画

近期我们推出了第一版UI2CODE,先计画于内部团队使用,利用使用的经验,让我们在叠代之下不断提高准确性。并且,我们正在调研结合NLP以及AST(语法树)的可能性,希望能够产出更有质量的代码。

我们也期望未来能将此工具开放于Flutter community,对于推动整个Flutter技术有所推进。希望能让更多人跟我们一起找寻更有效率的写代码方法,如果有任何想法欢迎与我们交流,我们也持续不断地在进化工具中,谢谢各位的阅读!

作者: 闲鱼技术-上叶,余晏

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码