如何构建一个理想UI代码表达的自动化工具?

简介:

作者:闲鱼技术-吉丰

基于设计师产出的 Sketch,甚至是一张 PNG,就能自动生成高可维护可扩展的 UI 代码,质量堪比一位资深前端工程师, 一定是一件让整个大前端领域都为之尖叫的事情。

出于这样一个让人兴奋的命题,闲鱼团队打造了 ui-automation 工具 。

背景

如何让前端,客户端的 UI 开发更有效率,一直是一个大前端领域热门话题。
从纯手写 UI 代码,到编写 XML 表达 UI,到所见即所得的 UI 编辑器。每一步都在极大提升着大前端领域的生产效率。
当下,随着计算机视觉技术,深度学习技术在工程侧的大量使用,闲鱼团队的同学们认为,基于当前的技术,是完全能够完成接近甚至超越资深前端工程师编写的理想的 UI 表达。

问题

类比基于传统的扫描算法和最新的 pix2code 的深度学习技术。它们确实在有些场景下,生成了渲染完全一致的 UI 代码,但是往往可维护性可扩展性差,除了在简单的静态页面中能有所应用,在大部分需要动态能力的场景,无能为力。
核心的生成的 UI 代码质量问题,是之前的这些工具无法跨越的鸿沟。
而闲鱼的 ui-automation 最核心的是要解决代码质量问题,使得生成的 UI 表达是最理想的,真正解放开发同学。

ui-automation 流程

  1. 信息提取 => 2. DSL 推导 => 3. 目标平台代码

相比于渲染流程

  1. ui 代码 => 2. gpu 渲染 => 3. 画面

是一个逆向的流程。

信息提取层

  1. 基于 Skecth 信息的提取和预处理

    信息全,精确,但是有冗余,干扰信息。
  2. 基于图片信息的提取

    信息干净,没有冗余信息。
    

DSL 层

将扁平化的上游信息,树形化,同时补充了完整的布局约束的信息。

模版层

根据上游的 DSL 信息, 生成不同平台的目标代码,如 flutter,weex 等。

undefined

本文重点阐述中间层 DSL 的定义和推导过程

基础 UI 元素

我们定义了 3 中最基础的 UI 元素
Shape,Text, Image。

结构上一个基础 UI 元素有一下几部分构成:

  1. 内容
  2. 渲染样式
  3. 布局样式

    布局样式沿用了经典 flexbox 的模型。
    

DSL 层的输入

输入中包含了上述 3 类基本的 UI 元素, 包含它们的内容,它们的渲染样式,以及相对屏幕的绝对坐标和大小,其中层级结构和布局属性在算法的推导中给出。

DSL 层的输出

输出是一个类似 dom 树的结构,有完整的布局属性,除了上述三类基础元素外,还有基础容器组件,CI 组件,BI 组件。

DSL 分层处理

在 DSL 的推导过程中, 分两大层

分组层

关注于宏观信息的处理。目标是完成一棵最佳的 ViewTree,以及扫描出足够的辅助信息给下一层属性推导使用。

(1)二元切分
对一组元素进行划分的时候
任何元素之间可能存在如下两种关系 1. 父子关系 2. 兄弟关系
根据两种关系的特点,我们使用了两个不同的模型来对数组切割(一分为二)。 1. 父子关系使用重合模型来划分。
重合模型会突出明显的若干个 background|foreground 图层 在 x,y 两个方向上都重合了剩下的所有元素。 2. 兄弟关系使用投影模型来划分。
投影模型,通过往一个方向上投影,兄弟关系的元素间 会存在明显的独立且连续分布的规律。两个方向都可投影的情况下, 优先水平方向。
在对重合模型和投影模型做适度优化后,第一次分组的容错性,稳定性,准确性得到了极大的提升。

一个简单的递归伪代码

Group(...children:View[]){}
type slice = ( views:View[] ) => View[][]  //sliceByOverlaps(views) || sliceByProjection(views)
const regroup = ( views:View[] ) => views.length === 1 ? views[0] : new Group(...slice(views).map(regroup))

经过上步骤切分后, 得到的是一棵标准意义上的二叉树。

undefined
例一:
注:7 号元素是简化的处理,实际包含了 3 个基础元素。
输入:

[3, 2, 1, 4, 5, 6, 7]

输出:

[
     3,
    [
        [2, 1],
        [
            4,
            [
                [5, 6],
                7
            ]
        ]
    ]
]

这样的一棵二叉树。

(2) 归并
标准意义上的二叉树, 并不符合我们的需求,所以需要做一次扁平化的归并,将同方向的父子节点归并为一个数组, 降低树的深度。
一个简单的递归伪代码

const flattenOnDirection = (view:View, parentDir: FlexDirection) => {
    return view.isContainer ?
        ? view.dir != null && view.dir == parentDir
            ? flatten(view.children.map(child => flattenOnDirection(child, view.dir)))
            : [flattenGroup(view)]
        : [view]
}

const flattenGroup = (view: View) => {
    if(view.isContainer) {
        view.children = flatten(node.children.map(l => flattenOnDirection(l, dir)), true)
    }
    return view
}

经过这层处理上例一的树修正为

[
     3,
    [
        [2, 1],
        4,
        [5, 6],
        7
    ]
]

(3) 排序层
根据容器方向,做一轮左到右,上至下的排序。

(4) 感知辅助线
对 ViewTree 做一次深度遍历, 扫描出辅助线的信息,将影响后续的对齐方式的推导,但并不影响 ViewTree 结构。
undefined
如上图, 灰色框表示基础元素,红色框比较容器,黄色虚线表示扫描出辅助线的信息。因为有辅助线信息的存在,我们才能让第 3 行的文字,左对齐,而非右对齐。人的视觉信息处理亦是如此。

(5) 疏密切分
根据疏密分布, 在对同一容器下的孩子节点,根据疏密分布切分。
undefined
如上图,同在水平方向的兄弟节点,根据疏密关系,分解为左族群和右族群,一个向左对齐,一个向右对齐,中间的剩余空间是共享的。

(6) 扫描网格分布信息
这里用到图形相似度的算法,若干水平行, 每行的元素子树之间相似。
在垂直方向扫描得到最大不重复的组合, 打破原有层级约束重新组合。
如:
undefined
扫描后, 打破原有层级约束后, 重新组合
undefined

(7) 感知中间线
对 ViewTree 做一次深度遍历, 扫描出有效的中间线信息,会影响 ViewTree 结构。

(8) 合并层 1. 合并背景图层到容器的背景属性 2. 合并背景图层到 Text 的背景属性 3. 合并仅包含一个孩子节点的容器

大致经过上述 8 个小层的处理后, 我们得到了一个理想的 ViewTree。下一步开始我们的属性推导。

属性推导层

关注于局部信息的深度推演。

(1) 推导每一个容器的方向
推导方向是最独立的,仅仅依赖于孩子节点的分布情况。

(2) 推导每一个节点是 在流里面的,还是脱离流绝对的
这里依赖一个重合冲突算法。大体是重合冲突率高的,就是绝对的元素,重合冲突率低的是流式元素。同时存在一定的冗余能力,允许小部分的重叠(负 margin),这样极大的提高了线性布局的动态性。

(3) 推导每一个节点的大小。
以一个尽力撑满的贪心模型,推导出每一个元素的大小。同时尽力用属性约束取代直接给定宽或定高的形式,来达元素大小是到跟随内容或跟随孩子节点或跟随父容器的动态性。
对于一个容器的副轴的大小的处理,会略微复杂些,

(4) 推导出一些特殊布局

  1. 网格
  2. 左右对齐布局

(5) 推导主轴方向对齐方式
优先居中, 其次居左, 最后居右。

(6) 推导副轴方向对齐方式

(7) 推导位置

  1. 流式元素 通过 margin 表示坐标。 居中通过(5)(6)推导的 JustifyContent,AlignItems,AlignSelf 等要素描述。
  2. 绝对元素 通过 left, top, bottom, right 等描述坐标。居中通过 transform 描述。

(8) 推导 padding

ui-automation 工具目前已经运用在闲鱼内部的各个业务场景之中,伴随着大量的应用,工具本身同样日益进化。

最后,闲鱼技术团队广招各类方向的达人,无论你是精通移动端,前端,后台,还是机器学习,音视频,自动化测试等,都欢迎投递简历加入我们,一同用技术改善生活!

相关文章
|
6天前
|
监控 jenkins 测试技术
自动化测试框架的构建与实践
【10月更文挑战第40天】在软件开发周期中,测试环节扮演着至关重要的角色。本文将引导你了解如何构建一个高效的自动化测试框架,并深入探讨其设计原则、实现方法及维护策略。通过实际代码示例和清晰的步骤说明,我们将一起探索如何确保软件质量,同时提升开发效率。
20 1
|
12天前
|
测试技术 开发者 Python
自动化测试之美:从零构建你的软件质量防线
【10月更文挑战第34天】在数字化时代的浪潮中,软件成为我们生活和工作不可或缺的一部分。然而,随着软件复杂性的增加,如何保证其质量和稳定性成为开发者面临的一大挑战。自动化测试,作为现代软件开发过程中的关键实践,不仅提高了测试效率,还确保了软件产品的质量。本文将深入浅出地介绍自动化测试的概念、重要性以及实施步骤,带领读者从零基础开始,一步步构建起属于自己的软件质量防线。通过具体实例,我们将探索如何有效地设计和执行自动化测试脚本,最终实现软件开发流程的优化和产品质量的提升。无论你是软件开发新手,还是希望提高项目质量的资深开发者,这篇文章都将为你提供宝贵的指导和启示。
|
1月前
|
运维 Linux Apache
Puppet 作为一款强大的自动化运维工具,被广泛应用于配置管理领域。通过定义资源的状态和关系,Puppet 能够确保系统始终处于期望的配置状态。
Puppet 作为一款强大的自动化运维工具,被广泛应用于配置管理领域。通过定义资源的状态和关系,Puppet 能够确保系统始终处于期望的配置状态。
54 3
|
14天前
|
Java 测试技术 持续交付
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
本文重点讲解如何搭建App自动化测试框架的思路,而非完整源码。主要内容包括实现目的、框架设计、环境依赖和框架的主要组成部分。适用于初学者,旨在帮助其快速掌握App自动化测试的基本技能。文中详细介绍了从需求分析到技术栈选择,再到具体模块的封装与实现,包括登录、截图、日志、测试报告和邮件服务等。同时提供了运行效果的展示,便于理解和实践。
52 4
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
|
10天前
|
安全 前端开发 测试技术
如何选择合适的自动化安全测试工具
选择合适的自动化安全测试工具需考虑多个因素,包括项目需求、测试目标、系统类型和技术栈,工具的功能特性、市场评价、成本和许可,以及集成性、误报率、社区支持、易用性和安全性。综合评估这些因素,可确保所选工具满足项目需求和团队能力。
|
11天前
|
运维 Ubuntu 应用服务中间件
自动化运维工具Ansible的实战应用
【10月更文挑战第36天】在现代IT基础设施管理中,自动化运维已成为提升效率、减少人为错误的关键手段。本文通过介绍Ansible这一流行的自动化工具,旨在揭示其在简化日常运维任务中的实际应用价值。文章将围绕Ansible的核心概念、安装配置以及具体使用案例展开,帮助读者构建起自动化运维的初步认识,并激发对更深入内容的学习兴趣。
33 4
|
12天前
|
运维 监控 数据安全/隐私保护
自动化运维工具的设计与实现
【10月更文挑战第34天】在现代IT基础设施管理中,自动化运维工具扮演着至关重要的角色。它们不仅提高了运维效率,还确保了服务的连续性和稳定性。本文将深入探讨如何设计并实现一个自动化运维工具,从需求分析到功能实现,再到最终的测试与部署。我们将通过一个简单的代码示例来展示如何自动执行常见的运维任务,如日志清理和性能监控。文章旨在为读者提供一套完整的方法论,以便他们能够构建自己的自动化运维解决方案。
|
28天前
|
运维 监控 jenkins
运维自动化实战:利用Jenkins构建高效CI/CD流程
【10月更文挑战第18天】运维自动化实战:利用Jenkins构建高效CI/CD流程
|
1月前
|
运维 关系型数据库 MySQL
自动化运维工具Ansible的实战应用
【10月更文挑战第9天】在现代IT运维领域,效率和可靠性是衡量一个系统是否健康的重要指标。自动化运维工具Ansible因其简洁、易用的特性,成为了众多企业和开发者的首选。本文将通过实际案例,展示如何利用Ansible进行日常的运维任务,包括配置管理、软件部署以及批量操作等,帮助读者深入理解Ansible的应用场景及其带来的效益。
|
1月前
|
运维 监控 测试技术
构建高效运维体系:从监控到自动化的实践之路
【10月更文挑战第9天】 在当今信息技术飞速发展的时代,运维作为保障系统稳定性与效率的关键角色,正面临前所未有的挑战。本文将探讨如何通过构建一个高效的运维体系来应对这些挑战,包括监控系统的搭建、自动化工具的应用以及故障应急处理机制的制定。我们将结合具体案例,分析这些措施如何帮助提升系统的可靠性和运维团队的工作效率。
52 1
下一篇
无影云桌面