女装网站建设的困难和不足,苏州苏网建设公司在建工程,金隅嘉华大厦网站建设公司,百度搜录提交入口背景
在《UI2CODE--整体设计》篇中#xff0c;我们提到UI2Code工程的整体流程。前步图片分析之后#xff0c;我们可以得到对应的DSL布局描述。利用DSL的资讯#xff0c;结合IntelliJ Plugin介面工具#xff0c;面向使用者提供生成对应Flutter代码。
本篇主要介绍我们如何…背景
在《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以及所属的类别(文字、图像、容器)利用下面的规则组合树的关系
图层之间的包裹关系例如某些图层为容器代表下面是可以挂其他节点的这边带有背景属性的容器我们定义称之为Shape区块式组件Block, 如ListView/GridView。可以将图层组成View item的关系闲鱼定义的组件资讯如CI以及BI这部份非闲鱼工程可以忽略重复布局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组件
接著处理的流程如下
首先判断所有Child内是否有多行文字或宽度固定的文字如果是的话针对其处理。需要加上Flex。若无以上的状况则判断Child间的Padding关系如果可拉伸的widget的Padding大于平均值的个数有多个则这些都加上Flex如果只有单个时则找寻最大Padding的widget(使用分群拉伸算法)最后但当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技术有所推进。希望能让更多人跟我们一起找寻更有效率的写代码方法如果有任何想法欢迎与我们交流我们也持续不断地在进化工具中谢谢各位的阅读
原文链接 本文为云栖社区原创内容未经允许不得转载。