从视觉稿到可运行的UI代码,这个过程到底有多费劲?端侧开发的同学对此应该深有体会。工作量大、技术深度有限,还伴随着视觉设计师一遍遍的走查和沟通,消耗实在不小。
闲鱼团队去年搞了一个很有意思的黑科技,直接从图片翻译成UI代码。具体效果,有一段演示视频可以看看。
为什么选择图片作为输入源?这可能是大多数人最好奇的问题。基于Sketch或Photoshop的插件,相对容易拿到确定性的信息,但图片的挑战更大,因为信息本身容易丢失。不过,选图片有几个关键原因:首先,图片是最终产出物,直观且确定;其次,这个链路对上游没有任何约束;最后,也是最重要的一点,基于图片的应用场景更普适。比如支持自动化测试,或者直接截取竞品的截图来套用数据源找体感,这些事其他方案很难做到。
上面说的是项目意义和选型判断,下面简单介绍下整体流程。
先是通过深度学习,检测出钱I单元,包括基础组件(比如imgview、textview),然后是自定义的BI组件(比如price),最后会寻找已经实现过的业务组件。下面这个图,展示了一个常见业务场景里的识别过程。

接下来,基于检测出的元素做元素提取,这个过程会分析系统渲染的原理,并结合OpenCV的方法来实现。
项目整体流程,用下面这张图来表示。

整个项目落地过程中,遇到不少技术难点,这里说两个有意思的。
第一个是架构问题。AutoUI的整个流程,是典型的上下游流水形式,每个关键单元都依赖上游的输出,并为下游提供标准输入。项目刚开始时,因为没有明确定义切分关系,经常出现一个人调整代码就影响整个链路的情况。后来做了一次架构升级,定义了“流式架构”——用一张图来帮助理解。

在这个单元里,定义了unit、task、server三个部分。unit是最小粒度的功能切分,task是unit的组合,server提供具体服务。每个部分都为上下游提供标准输入输出。这样切分的好处是,所有模块都有标准接口,可以通过模块的MOCK来实现标准化调试;基础功能完成后,还能像搭积木一样组合出想要的task和server。架构调整后,依赖关系大大减少,对项目快速迭代帮助很大。
后续在架构侧,还做了一个有意思的点:服务有些要跑在服务端,有些要跑在客户端上。所以设计了一个客户端和服务端同构的场景,希望开发人员只需要关心界面和服务的通信,而不需要关注具体部署关系。

上面说的是架构设计,接下来讲一个具体的布局问题解法:如何把静态的DSL转成合适的布局属性树。这部分分析了影响布局的因素,如下图所示。

这个非常常见的布局,拆解出了影响布局的部分:元素位置、间距、容器位置。参考了flex布局标准,也参考了新的grid布局标准,通过枚举元素在位置中的占比,来推导出对应关系。
不过后来还是遇到了一些Bad Case。要写出更贴近人写的UI代码,还得参考语义和相似度。比如上面这个例子,如果只靠枚举布局,很容易推断出四横列布局;但通过语义和相似度分析,就能合理推断出gridview布局。
去年,整个工程已经在业务侧跑起来了,大家从繁琐的切图工作中解放出来,去做更有价值的事。项目也展示给了Google团队,得到了不少关注。
展望未来,方向很清晰——通过更好的分析能力,包括容器识别、复杂背景识别、精确语义理解,产出更接近人写的代码,最终完全取代“切图”工作。此外,在弱交互、强展示的场景,比如导购或营销,通过数据模型抽象、固定PRD识别,有可能真正解放整段人力投入,让大家从偏确定性的需求实现中解放出来。同时,也在和D2C这样的项目一起共建,希望闲鱼已经实现的部分,能够解决更多问题,解放更多生产力。

