
本文由來自 Android Developer UX 團(tuán)隊(duì)的 Preethi Srinivas (UX 研究員) 和 Paris Hsu (交互設(shè)計(jì)師) 所撰寫。
Jetpack Compose 剛剛進(jìn)入 測試階段 啦!?? 在此激動(dòng)人心的時(shí)刻,Android Developer UX 團(tuán)隊(duì)想邀請您進(jìn)入我們的世界,走進(jìn)我們設(shè)計(jì) Compose Preview 的設(shè)計(jì)之旅,旅程將從理解我們面臨的挑戰(zhàn)、方向的形成,以及原型設(shè)計(jì)和評估開始。
背景: 理解挑戰(zhàn)
Jetpack Compose 是新一代 Android 開發(fā)的 UI 工具包,它可更簡單高效地構(gòu)建出精美且性能卓越的 Android 應(yīng)用。它使用了直觀的 Kotlin API,能夠做到 UI 隨著應(yīng)用狀態(tài)的變化而自動(dòng)更新。當(dāng)我們的團(tuán)隊(duì)第一次聽說這個(gè)項(xiàng)目時(shí),我們無比期待 Compose 項(xiàng)目的無限可能,它具有將邏輯和數(shù)據(jù)混合綁定到 UI 的潛力,以及為開發(fā)者解鎖新的能力。然而,這種新的構(gòu)建 UI 方式也帶來了新的設(shè)計(jì)挑戰(zhàn)。
對于經(jīng)典的 Android 視圖,UI 是靜態(tài)的,且主要是通過 XML 進(jìn)行創(chuàng)建。這意味著對 XML 的更改幾乎可以立即在 UI 中反映出來,我們可以根據(jù)這種特性來構(gòu)建像 Layout Editor 這樣的使用體驗(yàn),讓開發(fā)者們通過可視化的拖放操作來編輯他們應(yīng)用的布局,相應(yīng)的更改也會自動(dòng)映射到對 XML 的更改。然而,使用 Compose 的每一次修改,都必須編譯 Kotlin 代碼才能反映出變化,這就意味著需要花費(fèi)時(shí)間,從而減慢了迭代和創(chuàng)建的過程。
集思構(gòu)想: 沖刺設(shè)計(jì)方案
為了探究如何在 Compose 中支持這種開發(fā) UI 代碼的新模式,我們團(tuán)隊(duì)和我們的軟件工程師、開發(fā)者關(guān)系工程師和產(chǎn)品管理伙伴一起舉辦了一個(gè)研討會,以解決一個(gè)設(shè)計(jì)挑戰(zhàn): 我們?nèi)绾卫瞄_發(fā)者對現(xiàn)有工具的使用經(jīng)驗(yàn)來幫助他們創(chuàng)建和掌握 Compose UI?
我們基于 設(shè)計(jì)思維方法,從理解問題和調(diào)整問題的工作場景開始思考。這一過程需要團(tuán)隊(duì)在 "我們可以怎樣... (How Might We…)" 這一框架下寫出自己的想法,然后通過親和圖法 (affinitized) 去識別和提煉這些手頭的設(shè)計(jì)問題。我們以之前的研究為出發(fā)點(diǎn),將自己想象為開發(fā)者,結(jié)合實(shí)際開發(fā)過程會遇到的不同階段,來引導(dǎo)小組進(jìn)行思考,并繪制出解決方案的工具草圖。


這一設(shè)計(jì)研討會幫助我們總結(jié)了幾點(diǎn)核心原則,為 Compose Tooling 在 2020 年和之后的發(fā)展路線奠定了基礎(chǔ):
- 基于以往為 XML 構(gòu)建工具所積累的經(jīng)驗(yàn)為基礎(chǔ)
- 圍繞代碼進(jìn)行界面的繪制
- 優(yōu)化迭代和實(shí)驗(yàn)
這些原則構(gòu)成了我們產(chǎn)品設(shè)計(jì)理念前進(jìn)的基礎(chǔ)。例如,Compose Preview 構(gòu)建出的使用體驗(yàn)在外觀和使用上都會讓用戶覺得很熟悉,在此之上還補(bǔ)充了 Compose 的范式,通過輕量且可重復(fù)利用的 Composable 來構(gòu)建布局。設(shè)計(jì)研討會還鼓勵(lì)我們更多地以代碼為中心構(gòu)建出 REPL 的編程環(huán)境,使得開發(fā)者在預(yù)覽代碼時(shí)擁有更多的控制權(quán)和靈活性 — 這樣在本質(zhì)上就提供了一個(gè)支持迭代、實(shí)驗(yàn)和學(xué)習(xí)的交互式編程環(huán)境。我們還設(shè)想了提供超越 XML 之外的新體驗(yàn),例如 Interactive Preview (互動(dòng)預(yù)覽),它可以支持在 IDE 內(nèi)部被隔離的沙盒環(huán)境下的實(shí)時(shí)交互;Deploy Preview (部署預(yù)覽),用于在不重新運(yùn)行整個(gè)應(yīng)用的前提下,將 Preview Composable 部署到模擬器或者真機(jī)上。
原型設(shè)計(jì): 早期驗(yàn)證
為了驗(yàn)證我們的假設(shè)和設(shè)計(jì)路徑,我們開始對研討會中的想法進(jìn)行原型設(shè)計(jì),并在用戶研究案例中對其進(jìn)行測試。我們開設(shè)了一些研究,以便可以驗(yàn)證當(dāng)前的方向是否正確,并獲取關(guān)于未來想法和相關(guān)投入的反饋。我們選擇了一種迭代方法來獲取反饋,從而在涉及其他與 Compose 相關(guān)主題的多個(gè)研究中,將與 Preview 相關(guān)的主題進(jìn)行了折疊。
例如,為了解 Compose Preview 的使用體驗(yàn),我們首先列出開發(fā)者將會問出的問題:
- 開發(fā)者該如何使用 Compose Preview?
- 在什么情況下,開發(fā)者想要預(yù)覽動(dòng)態(tài)交互的效果?
- 在真機(jī)或模擬器上部署隔離式 Composable 并與之交互的功能對開發(fā)者的幫助程度如何?
我們邀請了開發(fā)者來加入我們的 Coding Session,在一個(gè)以研究為目的而創(chuàng)建的 Compose 項(xiàng)目中完成一些簡單的編程練習(xí)。這種方式節(jié)省了配置開發(fā)環(huán)境的時(shí)間和精力,尤其是 Compose 仍處于開發(fā)者預(yù)覽版之前的階段,這一方法還能夠幫助我們關(guān)注開發(fā)者在使用 Preview 和其他 Compose API 時(shí)的體驗(yàn)。早期的研究確實(shí)需要圍繞產(chǎn)品穩(wěn)定性的問題進(jìn)行展開,因?yàn)?Preview 并非總能按照預(yù)期正常工作。研究計(jì)劃預(yù)見到了這些不可避免的問題,同時(shí)也能夠提供非常早期的洞察。

從這些 Session 中我們發(fā)現(xiàn),一些開發(fā)者會在區(qū)分 Preview 工具欄上的 "Refresh" 圖標(biāo)和橫幅中的 "Refresh & Build" 圖標(biāo)時(shí)感到困惑。大多數(shù)開發(fā)者不會意識到 "Refresh" 只更新代碼而不需要完整構(gòu)建,而 "Refresh & Build" 則會通過構(gòu)建更新全部修改。
"如果 Refresh 和 Refresh & Build 希望保持一致,那么將它們放在一起會更好 — 我最初以為 Refresh 按鈕只會刷新 UI 而不會構(gòu)建項(xiàng)目。"

得到該反饋之后,我們決定將兩者統(tǒng)一起來,并改進(jìn)了體驗(yàn),當(dāng)用戶點(diǎn)擊圖標(biāo)或者橫幅時(shí),Preview 會根據(jù)代碼變化的情況來確定是需要進(jìn)行刷新還是重新構(gòu)建。
從早期幾輪開發(fā)者參與的研究中,產(chǎn)生了一個(gè)對于 Compose Preview 的深刻體會是,開發(fā)者在 Compose 中進(jìn)行 UI 原型設(shè)計(jì)時(shí),會感受到一種掌控感,以及工作效率的提升。
"Refresh 模式讓我可以快速完成 UI 的原型設(shè)計(jì)。加上可以使用功能強(qiáng)大的 Kotlin 創(chuàng)建 UI,以及利用 @Preview 函數(shù)展示實(shí)例數(shù)據(jù),比起老式的 XML 中提供的命名空間助手要好得多。"
我們還感受到了開發(fā)者在發(fā)現(xiàn) Preview 中同 Composable 交互時(shí)能夠?qū)Ш降綄?yīng)的代碼這一功能時(shí),他們所感到的驚訝和喜悅。
"我才發(fā)現(xiàn)這個(gè)功能,非常開心,我可以在 Preview 中點(diǎn)擊不同的視圖,直接跳轉(zhuǎn)到繪制該視圖的代碼里。我很期待在 Jetpack Compose 中看到更多類似的功能。"
在可用性研究中,我們觀察到開發(fā)者們會通過在 Preview 中點(diǎn)擊不同的 UI 元素來跳轉(zhuǎn)到項(xiàng)目的不同地方 — 這需要人們對 Preview 中的 UI 層次結(jié)構(gòu)有著較為深刻的理解。一些開發(fā)者發(fā)現(xiàn),當(dāng)在 Compose Preview 和代碼導(dǎo)航之間進(jìn)行交互時(shí),會有錯(cuò)位的問題出現(xiàn)。例如,在 Column 中的 Text Composable 區(qū)域之外點(diǎn)擊,會跳轉(zhuǎn)到代碼編輯器中定義 Column 的那一行中去。因而我們通過提供 Composable outline 來增強(qiáng) Preview 的使用體驗(yàn),以便在布局中圍繞 Composable 提供功能可見性。

沉浸式: 以日記形式進(jìn)行記錄
相對而言,在現(xiàn)場親自參與可用性研究更容易創(chuàng)造價(jià)值,并激發(fā)出新的想法。然而由于時(shí)間的限制,很難深入地去對主題進(jìn)行挖掘。因此,我們調(diào)整了研究方法,開始更多使用一種遠(yuǎn)程技術(shù),讓開發(fā)者自己對某個(gè) Compose 項(xiàng)目進(jìn)行幾周的使用。這段時(shí)間內(nèi),開發(fā)者需要寫日記,記錄他們在指定項(xiàng)目或者自己項(xiàng)目中關(guān)于工作流程上的一些問題。通常我們還會在幾周的探索之后,再搭配一次訪談,目的是為了更好了解開發(fā)者日記中的具體內(nèi)容。在幾天的探索之后,我們還邀請了一些開發(fā)者通過 Google Meet 的 Coding Session,來觀察并確定哪些部分的工作是進(jìn)展順利的,以及一些可以被改進(jìn)的地方。

在這些研究中出現(xiàn)了一點(diǎn)共性 — 開發(fā)者會使用 Preview 來創(chuàng)建工作流程,還會利用它進(jìn)行一些故障排除/驗(yàn)證的工作。例如,在創(chuàng)建 UI 時(shí),開發(fā)者會更傾向于使用 Refresh 模式,而在使用手勢/交互時(shí),他們會切換到 Interactive 模式,至于 Deploy 模式,則最常用于故障排除和驗(yàn)證檢查。
"當(dāng)我發(fā)現(xiàn)在 Interactive 模式下長按可以顯示星星的動(dòng)畫時(shí),我非常的開心。但是,之后的長按操作就不管用了 — 動(dòng)畫再也不出現(xiàn)了。通過在模擬器上部署 Preview 模式,我能確認(rèn)動(dòng)畫是可以正常工作的。如果 Interactive 模式能夠更加穩(wěn)定的話,它將會成為我測試交互性功能和動(dòng)畫的首選模式。有趣的是,在創(chuàng)建新的 UI 并查看它們的渲染方式時(shí),我大部分時(shí)間都不需要使用它。"
此外,我們從一些開發(fā)者那里得到反饋,在考慮整個(gè)布局之前,能夠提取并集中實(shí)現(xiàn)一個(gè)單獨(dú)的 Composable 的重要性。
"只部署 Preview 意味著我不需要為了測試一個(gè)新的組件,而把 UI 關(guān)聯(lián)到實(shí)際的流程中 (包含多個(gè)界面和用戶輸入)。這樣使得調(diào)試 + 改變復(fù)雜 UI 變得更加容易。"
將想法付諸于行動(dòng)
我們在研究的基礎(chǔ)之上確立了要前進(jìn)的方向,這有助于將開發(fā)人員對我們工具的見解和遇到的問題反饋到我們的產(chǎn)品迭代中 — 同時(shí)能確保我們也能夠捕獲到新興的主題來塑造我們的設(shè)計(jì)理念。以下是幾個(gè)示例:
Preview 新用戶的使用體驗(yàn)
我們發(fā)現(xiàn)開發(fā)者在探索如何開始創(chuàng)建 Preview 時(shí)會有困難 — 很多人在示例項(xiàng)目中留意到了 Preview,但是在自己的項(xiàng)目中就不能夠復(fù)刻出類似的使用體驗(yàn)。不直觀的設(shè)計(jì)往往導(dǎo)致在創(chuàng)建 Preview Composable 時(shí),對 Compose 編譯器到底支持什么功能而產(chǎn)生誤解。例如,我們觀察到一些開發(fā)者試圖預(yù)覽一個(gè)接受參數(shù)的 Composable,而這一功能 Compose 是不支持的。在這種情況下,編譯器提供的錯(cuò)誤信息往往會被忽略或遺漏。
"我無法在 Preview 中顯示 Split 視圖,即使我是直接從一個(gè)示例項(xiàng)目中復(fù)制過來的代碼,它也無法讓 Preview 注解正常工作。"
這一重要的發(fā)現(xiàn)使我們引入了默認(rèn)狀態(tài),如果 Kotlin 文件尚未定義 Preview Composable,那么拆分編輯器 (這一概念源于 View/XML 世界中的 Preview) 則始終處于可見狀態(tài)。我們相信該解決方案不僅可以提高對 Preview 的認(rèn)知和發(fā)現(xiàn)能力,還可以提供創(chuàng)建和操作 Preview 相關(guān)的學(xué)習(xí)經(jīng)驗(yàn)。

增強(qiáng)編碼體驗(yàn)
在調(diào)查研究中,開發(fā)者問了我們這樣幾個(gè)問題:
- 如何在淺色和深色主題背景中預(yù)覽一個(gè)布局?
- 如何利用樣本數(shù)據(jù)預(yù)覽一個(gè)布局?
- 我如何利用 Preview 來確定我的代碼中在哪定義了某個(gè)特定的 UI 元素?
- 有沒有一種方法可以讓 Compose 模仿 View/XML 世界中的 Preview 使用體驗(yàn),特別是在 Preview 中如何快速查看因?yàn)榇a變化產(chǎn)生的視覺變化?
這些問題都指向了一點(diǎn) — 開發(fā)者正在尋找一種快速簡單的機(jī)制來操作 Preview,并期望它能更快地進(jìn)行迭代。
我們將繼續(xù)對開發(fā)者反饋的新功能進(jìn)行原型設(shè)計(jì)和測試,例如 Preview Configuration Picker (Preview 配置選擇器),它允許開發(fā)者可視化地配置他們的布局 (例如在不同的主題、設(shè)備、語言等),以提高 @Preview API 的可發(fā)現(xiàn)性和可學(xué)習(xí)性。

另一個(gè)例子是 Live literals (實(shí)時(shí)顯示字面量類型),這是來自工程團(tuán)隊(duì)的解決方案,通過在 Preview 面板中對一些 Composable 值 (例如 Boolean、Char、String、Color 等) 引入實(shí)時(shí)更新,來優(yōu)化迭代開發(fā)的速度。

PreviewParameterProvider 是我們將樣本數(shù)據(jù)納入 Preview 中來允許真實(shí)上下文測試的又一例子。

旅程仍未結(jié)束
我們希望這篇文章能讓您了解我們是如何根據(jù)您的反饋來改進(jìn) Compose Preview 的。當(dāng)然,我們的旅程并沒有就此結(jié)束!我們還有很多繼續(xù)改善 Compose Preview 及其工具使用體驗(yàn)的計(jì)劃。例如,將 Live Literals 功能擴(kuò)展到字面量類型之外,以繼續(xù)優(yōu)化迭代開發(fā)的速度。
如果您在使用 Compose 工具時(shí)遇到問題,或者是有任何可以改善使用體驗(yàn)的新功能的想法,請 告訴我們。我們也在尋找開發(fā)者參與到用戶研究 Session 中,您可以 注冊 參與。