本文由来自 Android Developer UX 团队的 Preethi Srinivas (UX 研究员) 和 Paris Hsu (交互设计师) 所撰写。
Jetpack Compose 刚刚进入 测试阶段 啦! 在此激动人心的时刻,Android Developer UX 团队想邀请您进入我们的世界,走进我们设计 Compose Preview 的设计之旅,旅程将从理解我们面临的挑战、方向的形成,以及原型设计和评估开始。
背景: 理解挑战
Jetpack Compose 是新一代 Android 开发的 UI 工具包,它可更简单高效地构建出精美且性能卓越的 Android 应用。它使用了直观的 Kotlin API,能够做到 UI 随着应用状态的变化而自动更新。当我们的团队第一次听说这个项目时,我们无比期待 Compose 项目的无限可能,它具有将逻辑和数据混合绑定到 UI 的潜力,以及为开发者解锁新的能力。然而,这种新的构建 UI 方式也带来了新的设计挑战。
对于经典的 Android 视图,UI 是静态的,且主要是通过 XML 进行创建。这意味着对 XML 的更改几乎可以立即在 UI 中反映出来,我们可以根据这种特性来构建像 Layout Editor 这样的使用体验,让开发者们通过可视化的拖放操作来编辑他们应用的布局,相应的更改也会自动映射到对 XML 的更改。然而,使用 Compose 的每一次修改,都必须编译 Kotlin 代码才能反映出变化,这就意味着需要花费时间,从而减慢了迭代和创建的过程。
集思构想: 冲刺设计方案
为了探究如何在 Compose 中支持这种开发 UI 代码的新模式,我们团队和我们的软件工程师、开发者关系工程师和产品管理伙伴一起举办了一个研讨会,以解决一个设计挑战: 我们如何利用开发者对现有工具的使用经验来帮助他们创建和掌握 Compose UI?
我们基于 设计思维方法,从理解问题和调整问题的工作场景开始思考。这一过程需要团队在 “我们可以怎样… (How Might We…)” 这一框架下写出自己的想法,然后通过亲和图法 (affinitized) 去识别和提炼这些手头的设计问题。我们以之前的研究为出发点,将自己想象为开发者,结合实际开发过程会遇到的不同阶段,来引导小组进行思考,并绘制出解决方案的工具草图。
Compose 设计研讨会
这一设计研讨会帮助我们总结了几点核心原则,为 Compose Tooling 在 2020 年和之后的发展路线奠定了基础:
- 基于以往为 XML 构建工具所积累的经验为基础
- 围绕代码进行界面的绘制
- 优化迭代和实验
这些原则构成了我们产品设计理念前进的基础。例如,Compose Preview 构建出的使用体验在外观和使用上都会让用户觉得很熟悉,在此之上还补充了 Compose 的范式,通过轻量且可重复利用的 Composable 来构建布局。设计研讨会还鼓励我们更多地以代码为中心构建出 REPL 的编程环境,使得开发者在预览代码时拥有更多的控制权和灵活性 — 这样在本质上就提供了一个支持迭代、实验和学习的交互式编程环境。我们还设想了提供超越 XML 之外的新体验,例如 Interactive Preview (互动预览),它可以支持在 IDE 内部被隔离的沙盒环境下的实时交互;Deploy Preview (部署预览),用于在不重新运行整个应用的前提下,将 Preview Composable 部署到模拟器或者真机上。
原型设计: 早期验证
为了验证我们的假设和设计路径,我们开始对研讨会中的想法进行原型设计,并在用户研究案例中对其进行测试。我们开设了一些研究,以便可以验证当前的方向是否正确,并获取关于未来想法和相关投入的反馈。我们选择了一种迭代方法来获取反馈,从而在涉及其他与 Compose 相关主题的多个研究中,将与 Preview 相关的主题进行了折叠。
例如,为了解 Compose Preview 的使用体验,我们首先列出开发者将会问出的问题:
- 开发者该如何使用 Compose Preview?
- 在什么情况下,开发者想要预览动态交互的效果?
- 在真机或模拟器上部署隔离式 Composable 并与之交互的功能对开发者的帮助程度如何?
我们邀请了开发者来加入我们的 Coding Session,在一个以研究为目的而创建的 Compose 项目中完成一些简单的编程练习。这种方式节省了配置开发环境的时间和精力,尤其是 Compose 仍处于开发者预览版之前的阶段,这一方法还能够帮助我们关注开发者在使用 Preview 和其他 Compose API 时的体验。早期的研究确实需要围绕产品稳定性的问题进行展开,因为 Preview 并非总能按照预期正常工作。研究计划预见到了这些不可避免的问题,同时也能够提供非常早期的洞察。
通过 Coding Session 进行可用性研究
从这些 Session 中我们发现,一些开发者会在区分 Preview 工具栏上的 “Refresh” 图标和横幅中的 “Refresh & Build” 图标时感到困惑。大多数开发者不会意识到 “Refresh” 只更新代码而不需要完整构建,而 “Refresh & Build” 则会通过构建更新全部修改。
“如果 Refresh 和 Refresh & Build 希望保持一致,那么将它们放在一起会更好 — 我最初以为 Refresh 按钮只会刷新 UI 而不会构建项目。”
预览 Refresh & Build (之前和之后)
得到该反馈之后,我们决定将两者统一起来,并改进了体验,当用户点击图标或者横幅时,Preview 会根据代码变化的情况来确定是需要进行刷新还是重新构建。
从早期几轮开发者参与的研究中,产生了一个对于 Compose Preview 的深刻体会是,开发者在 Compose 中进行 UI 原型设计时,会感受到一种掌控感,以及工作效率的提升。
“Refresh 模式让我可以快速完成 UI 的原型设计。加上可以使用功能强大的 Kotlin 创建 UI,以及利用 @Preview 函数展示实例数据,比起老式的 XML 中提供的命名空间助手要好得多。”
我们还感受到了开发者在发现 Preview 中同 Composable 交互时能够导航到对应的代码这一功能时,他们所感到的惊讶和喜悦。
“我才发现这个功能,非常开心,我可以在 Preview 中点击不同的视图,直接跳转到绘制该视图的代码里。我很期待在 Jetpack Compose 中看到更多类似的功能。”
在可用性研究中,我们观察到开发者们会通过在 Preview 中点击不同的 UI 元素来跳转到项目的不同地方 — 这需要人们对 Preview 中的 UI 层次结构有着较为深刻的理解。一些开发者发现,当在 Compose Preview 和代码导航之间进行交互时,会有错位的问题出现。例如,在 Column 中的 Text Composable 区域之外点击,会跳转到代码编辑器中定义 Column 的那一行中去。因而我们通过提供 Composable outline 来增强 Preview 的使用体验,以便在布局中围绕 Composable 提供功能可见性。
Preview 代码跳转功能
沉浸式: 以日记形式进行记录
相对而言,在现场亲自参与可用性研究更容易创造价值,并激发出新的想法。然而由于时间的限制,很难深入地去对主题进行挖掘。因此,我们调整了研究方法,开始更多使用一种远程技术,让开发者自己对某个 Compose 项目进行几周的使用。这段时间内,开发者需要写日记,记录他们在指定项目或者自己项目中关于工作流程上的一些问题。通常我们还会在几周的探索之后,再搭配一次访谈,目的是为了更好了解开发者日记中的具体内容。在几天的探索之后,我们还邀请了一些开发者通过 Google Meet 的 Coding Session,来观察并确定哪些部分的工作是进展顺利的,以及一些可以被改进的地方。
通过提问式的日记来帮助反馈的获取
在这些研究中出现了一点共性 — 开发者会使用 Preview 来创建工作流程,还会利用它进行一些故障排除/验证的工作。例如,在创建 UI 时,开发者会更倾向于使用 Refresh 模式,而在使用手势/交互时,他们会切换到 Interactive 模式,至于 Deploy 模式,则最常用于故障排除和验证检查。
“当我发现在 Interactive 模式下长按可以显示星星的动画时,我非常的开心。但是,之后的长按操作就不管用了 — 动画再也不出现了。通过在模拟器上部署 Preview 模式,我能确认动画是可以正常工作的。如果 Interactive 模式能够更加稳定的话,它将会成为我测试交互性功能和动画的首选模式。有趣的是,在创建新的 UI 并查看它们的渲染方式时,我大部分时间都不需要使用它。”
此外,我们从一些开发者那里得到反馈,在考虑整个布局之前,能够提取并集中实现一个单独的 Composable 的重要性。
“只部署 Preview 意味着我不需要为了测试一个新的组件,而把 UI 关联到实际的流程中 (包含多个界面和用户输入)。这样使得调试 + 改变复杂 UI 变得更加容易。”
将想法付诸于行动
我们在研究的基础之上确立了要前进的方向,这有助于将开发人员对我们工具的见解和遇到的问题反馈到我们的产品迭代中 — 同时能确保我们也能够捕获到新兴的主题来塑造我们的设计理念。以下是几个示例:
Preview 新用户的使用体验
我们发现开发者在探索如何开始创建 Preview 时会有困难 — 很多人在示例项目中留意到了 Preview,但是在自己的项目中就不能够复刻出类似的使用体验。不直观的设计往往导致在创建 Preview Composable 时,对 Compose 编译器到底支持什么功能而产生误解。例如,我们观察到一些开发者试图预览一个接受参数的 Composable,而这一功能 Compose 是不支持的。在这种情况下,编译器提供的错误信息往往会被忽略或遗漏。
“我无法在 Preview 中显示 Split 视图,即使我是直接从一个示例项目中复制过来的代码,它也无法让 Preview 注解正常工作。”
这一重要的发现使我们引入了默认状态,如果 Kotlin 文件尚未定义 Preview Composable,那么拆分编辑器 (这一概念源于 View/XML 世界中的 Preview) 则始终处于可见状态。我们相信该解决方案不仅可以提高对 Preview 的认知和发现能力,还可以提供创建和操作 Preview 相关的学习经验。
Preview 默认状态
增强编码体验
在调查研究中,开发者问了我们这样几个问题:
- 如何在浅色和深色主题背景中预览一个布局?
- 如何利用样本数据预览一个布局?
- 我如何利用 Preview 来确定我的代码中在哪定义了某个特定的 UI 元素?
- 有没有一种方法可以让 Compose 模仿 View/XML 世界中的 Preview 使用体验,特别是在 Preview 中如何快速查看因为代码变化产生的视觉变化?
这些问题都指向了一点 — 开发者正在寻找一种快速简单的机制来操作 Preview,并期望它能更快地进行迭代。
我们将继续对开发者反馈的新功能进行原型设计和测试,例如 Preview Configuration Picker (Preview 配置选择器),它允许开发者可视化地配置他们的布局 (例如在不同的主题、设备、语言等),以提高 @Preview API 的可发现性和可学习性。
Preview 配置选择器
另一个例子是 Live literals (实时显示字面量类型),这是来自工程团队的解决方案,通过在 Preview 面板中对一些 Composable 值 (例如 Boolean、Char、String、Color 等) 引入实时更新,来优化迭代开发的速度。
Live Literal 的实际体验
PreviewParameterProvider 是我们将样本数据纳入 Preview 中来允许真实上下文测试的又一例子。
使用 PreviewParameterProvider
旅程仍未结束
我们希望这篇文章能让您了解我们是如何根据您的反馈来改进 Compose Preview 的。当然,我们的旅程并没有就此结束!我们还有很多继续改善 Compose Preview 及其工具使用体验的计划。例如,将 Live Literals 功能扩展到字面量类型之外,以继续优化迭代开发的速度。
如果您在使用 Compose 工具时遇到问题,或者是有任何可以改善使用体验的新功能的想法,请 告诉我们。我们也在寻找开发者参与到用户研究 Session 中,您可以 注册 参与。