设计稿(UI视图)自动生成代码方案的探索
?
設計稿(UI視圖)轉代碼是前端工程師日常不斷重復的工作,這部分工作復雜度較低但工作占比較高,所以提升設計稿轉代碼的效率一直是前端工程師追求的方向之一。
?
此前,前端工程師嘗試過將業務組件模塊化構建成通用視圖庫,并通過拖拽、拼接等形式搭建業務模塊,從而實現視圖復用,降低設計稿轉代碼的研發成本。但隨著業務的發展和個性化的驅動,通用視圖庫無法覆蓋所有應用場景,本文提出了一種設計稿自動生成代碼的方案。
1 背景
設計稿(UI視圖)轉代碼是前端工程師日常不斷重復的工作,這部分工作復雜度較低但工作占比較高,所以提升設計稿轉代碼的效率一直是前端工程師追求的方向之一。此前,前端工程師嘗試過將業務組件模塊化構建成通用視圖庫,并通過拖拽、拼接等形式搭建業務模塊,從而實現視圖復用,降低設計稿轉代碼的研發成本。但隨著業務的發展和個性化的驅動,通用視圖庫無法覆蓋所有應用場景,本文提出了一種設計稿自動生成代碼的方案。
目前,業內主流的代碼生成方案有兩種,一種是通過訓練神經網絡,從圖片或草圖直接生成代碼,以微軟sketch2json為代表;另一種是基于Sketch源文件,從中解析出圖層信息轉化成DSL并生成代碼,以imgCook為代表。
經過實踐,我們發現第一種方案基于神經網絡的代碼生成算法雖然簡單粗暴,但復雜層布局的準確率較低、可解釋程度不高導致后續無法持續優化。方案二中Sketch源文件信息量豐富、算法自定義程度高、優化空間大。因此,我們調研了業界基于Sketch的代碼自動生成方案(已對外公布或者開源),發現了一些不足并嘗試解決,下面從算法準確率、代碼可讀性、研發流程覆蓋度等方面做一下對比(該對比結果僅考察業界方案對我們自己業務的適用性,實際結果可能存在差異):
-
算法準確率方面:淘寶imgCook支持基于AI的組件識別,不支持成組布局,準確率中等(從官網了解到可以識別循環布局,但不能識別出測試樣本中的循環布局),58 Picasso僅支持原始組件的識別,復雜組件生成錯誤較多,不支持成組/懸浮/循環布局,準確率較低。
-
代碼可讀性方面:淘寶imgCook在生成布局時,測試樣本中圖層重疊區域使用到了基于根布局的絕對定位方式,不符合RD預期,可讀性一般,而我們的方案使用相對定位方式,可讀性較好。
-
研發流程覆蓋度方面:淘寶imgCook從RD視角構建了一個IDE,支持在IDE中完成樣式調整、邏輯綁定;而我們的方案從產研協作視角出發,支持數據、邏輯、埋點的可視化配置及上線。
2 方案介紹
如圖所示,配置平臺主要分成三塊包括:設計稿轉視圖樹(UI2DSL)、視圖樹轉代碼(DSL2Code)、以及業務信息綁定,下面簡單介紹一下每一塊的作用。
-
設計稿轉DSL視圖樹(UI2DSL):將設計稿轉化成平臺無關的DSL視圖樹。
-
視圖樹轉代碼(DSL2Code):將DSL視圖樹轉化成基于Flex布局的MTFlexBox靜態代碼。
-
業務信息綁定:提供可視化配置工具,支持MTFlexBox靜態代碼綁定后臺數據、業務邏輯、以及曝光/點擊等埋點邏輯。
2.1 設計稿轉視圖樹(UI2DSL)
UI2DSL主要經歷以下四個步驟:
2.1.1 設計稿導入
在日常開發過程中,我們接觸比較多的組件有按鈕、標題、進度條、評分組件等,但是Sketch數據源中并沒有這些組件只有圖層信息,圖層是設計師在設計UI視圖時用到的視圖控件。組件與圖層的對應關系是一對多的關系,圖層在Sketch數據源中的表現形式如下圖中的JSON數據結構所示,描述了圖層的坐標、大小等信息,后續布局生成就是基于對圖層的切割來實現的。
[{"class_name":"MSTextLayer","font_face":"PingFangSC-Medium","font_size":13.44,"height":36.5,"index":8,"line_height":18.24,"name":"恒都民生精選豬小排帶骨400g±25g","object_id":"EF55F482-A690-4EC2-8A6E-6E7D2C6A9D91","opacity":0.9000000357627869,"text":"恒都民生精選豬小排帶骨400g±25g","text_align":"left","text_color":"#FF000000","type":"text","width":171.8,"x":164.2,"y":726.7},//...... ]2.1.2 組件識別
從上面的數據源可以看出,圖層有圖片、文字、矩形等基本類型,在組件識別這一步圖層需要被轉化成文字/圖片/進度條/評分組件/價格組件/角標等日常開發使用的組件類型。但是,目前我們的進展還停留在只能將圖層識別為文字或者圖片的階段,后續我們將接入淘寶開源的pipcook框架,基于神經網絡算法進行更加豐富的組件類型識別。
2.1.3 可視化干預
設計稿作為輸入源是設計稿自動轉代碼的基礎,這對設計稿的設計規范要求較高。但在實踐中,我們發現設計師會利用Sketch中的基本圖形(每個圖形最終形成數據源中的一個圖層)疊加來描述一個組件的視覺效果,因此設計稿中不可避免會出現冗余圖層的問題,干擾DSL的生成。
雖然我們也嘗試了利用自動化的手段刪除冗余圖層,但對于算法不能識別的部分(例如:圖片上有一個文本圖層,但是實際情況中文本是顯示在圖片里的,這個時候無法從算法層面決定是否刪除文本),仍然需要靠人工進行圖層刪除、合并等,否則無法正常生成DSL。設計稿主要有以下幾類問題。
圖層未合并
上圖是從設計稿解析出來的結果,可以發現在“美團優選”文字上方的圖片中有很多紅色的矩形框(每個矩形框是一個單獨的圖層),而算法預期的輸入是一個圖層,因此需要在算法處理前將多個圖層合并成一個圖層,右側的三張圖也有類似問題。我們與設計同學進行過溝通,設計同學表示愿意在產出設計稿之前將圖層進行合并,但由于目前無法提供檢測機制(圖層合并是否有遺漏無法自動檢測出來),也就無法徹底避免圖層未合并的問題。
圖層位置交叉
實踐中發現當設計稿中不同字體/大小/顏色的文字排列在一起時,解析出來的圖層信息往往會出現重疊的情況,由于DSL視圖樹算法依賴位置來確定不同組件的約束關系,因此位置的交叉會對算法準確度造成較大的影響。
復雜背景圖層
上圖中紅色背景是由2個圖層(2個藍色矩形框)拼接形成的,左圖上的藍色圖層是純色,右圖上的藍色圖層是漸變色,在兩個圖層未合并的情況下,算法生成的代碼將會出錯。
上面提出的問題,通過約束設計師來達到設計稿的規范化,難度較大,所以我們提供了可視化干預工具。下面對上述問題做一個簡單的總結:
-
問題一:圖層未合并問題肉眼很容易識別出來,利用工具將冗余圖層進行快速合并刪除即可。
-
問題二:圖層交叉問題肉眼不易識別,因此我們提供了檢測工具,基于檢測工具可以對設計稿中的交叉問題快速修復。
-
問題三:復雜背景問題肉眼不易識別,暫時也沒有有效的檢測工具,用戶可以采用邊干預邊生成的方式生成DSL。
可視化干預是重要的一環,經過可視化干預,將不標準的設計稿轉化為標準的圖層信息后再輸入給算法,可以極大地提升算法的準確率。這里我們和imgCook的處理方式有一個區別:imgCook在引入了閾值處理等算法后(更智能,出錯概率更大),可視化干預能力主要體現在事后,而我們在生成DSL之前允許用戶對圖層進行干預,在干預時用戶面對的是直觀的圖層信息,可以有效降低工具的使用門檻(更穩定,效果更好)。
2.1.4 視圖樹生成
將扁平的數據源轉化為樹狀結構的DSL,這個過程如果是人腦來做會怎么思考呢?先確定布局的整體結構是行布局或者列布局,然后再確定局部區域應該是什么布局結構,最后組裝起來形成視圖樹。這個過程與遞歸算法類似,因此我們采用了遞歸算法作為算法的主框架,同時引入了“橫豎切割+布局結構+模型評估”三大利器。
利器一:橫豎切割
生成DSL時采用了整分的思路,即將大布局不斷的切分成小布局,下面以動畫的形式看一下簡化過的DSL生成過程:
將設計稿一部分區域視為一個子區域,最開始的時候子區域和整個模板的面積一樣大,基于圖層的位置、大小信息,計算每個圖層的上/下/左/右邊緣坐標與其他圖層的相對關系,就可以尋找到切割點(如上圖中紅色箭頭所指的位置)。接下來依據切割點,將子區域切割成更小的子區域,在切割的過程中如果切割點是橫向的,則生成列布局;如果切割點是縱向的,則生成行布局。通過不斷的切割子區域得到更小的子區域,直到所有的子區域只剩下圖片或者文本等不可切割的圖層,這樣就可以生成完整的DSL視圖樹了。為了方便讀者理解,圖例中只演示了行布局、列布局的切分過程,實際情況還包含了其他布局類型,會要復雜許多。
這里還要注意一個問題,當有3個切割點時,我們選擇了直接將子區域切割成4個子區域,實際上我們可以只選擇1個切割點進行切割,也可以選擇2個切割點進行切割,當有N個切割點時,實際上存在(N的階乘+1)種切割方式,具體選擇哪種切割方式,我們會在利器三中討論。
利器二:布局結構
每個圖層都是一個矩形,為了生成布局結構只能依賴矩形的上下左右坐標信息。因此,對布局結構進行分類時,我們根據矩形與矩形之間的位置關系(相交、相離和包含關系)做了以下分類。
注意:從生成DSL的結果來看,包含布局和成組布局的處理方式其實是一樣的,都是使用類似于FrameLayout的層疊布局包含內部圖層元素,但是我們仍然保持分類原則(矩形之間的位置關系)不變。
上圖中,相離、包含比較好理解,為什么兩個圖層相交的時候,會有成組和懸浮兩種類型的布局結構呢?我們看下上述成組布局、懸浮布局兩個設計稿中分別標出了相交的元素A、B,它們在位置上的相對關系是一樣的,都是A、B兩個圖層對應的矩形框發生了交叉。但是我們希望理想態的DSL視圖樹卻有所差異,如下圖所示:
-
成組布局中:A、B邏輯上是一個整體,交叉是必然的,最終DSL中A、B被層疊布局包含,層疊布局中沒有其他元素。
-
懸浮布局中:A、B邏輯上不是整體,只是碰巧交叉了,最終DSL中A、B分別在不同的層級中。
因此,對于圖層相交時可能有兩種類型的布局結構,分別是成組布局和懸浮布局。從上圖可以看出使用成組布局還是懸浮布局是由圖層內容決定的,那么就需要算法理解圖層內容了,比如基于AI構建樣本庫,記住所有的角標樣式(上面表格中4描述的),下次遇到角標相交時就生成成組布局。
考慮到AI模型也是對規則的抽象,我們先搭建一套自定義識別規則。成組布局其位置信息是有規律可循的,例如:角標經常出現在右上角,標簽經常出現在左上角,頭像經常橫向或者縱向交叉等,因此我們針對圖層之間的位置關系構建了交叉模型,如下圖所示:
上圖的交叉模型可以記住歷史模板中成組布局圖層之間的位置關系,下次遇到相交布局時判斷是否在歷史規則庫中即可完成識別,如果在就按成組布局處理否則按照懸浮布局處理。下圖是通過歷史模板構建的成組規則庫。
上面介紹了本方案中涉及的5種布局類型,目前來看這五種布局類型可以描述所有的模板布局,并且生成代碼符合RD的預期。下面展示兩個設計稿DSL實例:
利器三:模型評估
在介紹橫豎切割時,可以看到當存在多個切割點時,對所有切割點同時進行了切割,但實際上算法在切割時復雜度會更高,當有三個切割點時,實際上有5種切割方式,每種切割方式都會生成一個DSL。既然有5種切割方式,那么到底應該選擇哪一種DSL呢?模型評估算法就是用來解決這個問題的。
目前模型評估算法有兩個指標:布局節點數和逆布局指數。
-
DSL中布局節點數越少,切割方式越好。
-
逆布局指數用來評估DSL中的行列布局的合理程度,其中逆布局指數越大越不合理,反之,逆布局指數越小,切割方式越好。
以下圖為例,看下視圖不同切割方式下對應的模型評估方式:
如果模型評估算法只衡量布局節點數的話,那么會選擇第一種切割方式生成的DSL作為最終的結果。但實際上,第二種切割方式更加合理。在切割方式一中,廣告、立即預約處于一個列布局中,但是橫向對齊方式(交叉軸)卻不一樣,“廣告”是右對齊,“立即預約”是左對齊,逆布局指數表示交叉軸對齊方式不一致的節點數量,因此通過逆布局指數,我們可以規避掉不合理的切割方式。
2.1.5 列表布局
上一節介紹了基本的布局結構,雖然說這些布局結構已經可以描述所有的UI布局,但是與RD的編碼習慣還是有一些差異。
對于上面的布局,RD通常不會把相同的item寫五遍,而是會將item放在一個類似于ListView的列表組件中,使代碼看起來簡潔易懂。因此在DSL生成階段,除了識別基本的行/列/包含/成組/懸浮布局外,還需要進一步識別行/列布局中的元素是否形成列表布局。
在試驗過程中,我們發現列表布局分為兩種:單狀態列表組件和多狀態列表組件。上圖中每一個item的布局結構都是一樣的,我們稱為單狀態列表組件,再來看一下多狀態列表組件(如下圖所示),每個item有多種狀態(選中態和非選中態),并且不同狀態的布局結構不一致。
對行/列布局中單狀態列表組件的識別,只需要比較item子視圖樹的結構,子視圖樹結構一致則判斷為單狀態列表組件。對多狀態列表組件的識別我們采取了自動識別+人工干預的方式,自動識別的方式比較粗暴,只要行列布局中子item的寬/高接近,并且子item不是基本組件(基本組件容易形成誤判),就判定為多狀態列表組件。具體算法是計算子item寬高的標準差,小于閾值就判定為多狀態列表組件,否則不是。公式如下:
那為什么還要人工干預呢?因為是否使用列表組件其實與產品邏輯相關,但是目前我們無法將產品文檔中的邏輯識別出來,只能盡可能識別出所有的多狀態列表組件,并允許用戶對生成結果進行變更。比如上述送戀人的設計稿,產品可能約定每一個item都有選中態/非選中態兩種狀態,也可能是從業務角度考慮需要著重突出送戀人這個item,這時每個item就只有一種確定的狀態,這兩種不同的產品邏輯在編寫代碼時有不同的最優技術方案。
2.2 視圖樹轉代碼(DSL2Code)
DSL視圖樹只是生成代碼的中間產物,還需要對DSL進行代碼還原,DSL2Code主要包括兩個步驟:屬性推斷、屬性信息調整。
2.2.1 屬性推斷
屬性推斷包括兩個部分:樣式屬性和結構屬性。樣式屬性包括字體、背景色、圓角等可以直接通過數據源信息中獲取得到的屬性;結構屬性包括大小、內外邊距、主輔軸對齊等結構信息,這些信息無法從數據源中直接獲取,所以結構信息的推斷是這部分工作的重點。
結構信息推斷算法同樣使用遞歸算法作為主框架,通過一次遞歸對所有元素進行兩次遍歷來完成結構信息的推斷。如下圖所示,在對DSL所有節點進行遞歸遍歷時,把所有元素依次加入隊列中,遞歸完成后,再把所有節點依次移出隊列,這樣一進一出便對所有元素完成了兩次遍歷,我們把這兩次遍歷稱為進隊遍歷和出隊遍歷。
進隊遍歷時,推斷算法根據數據源中信息記錄每個節點的大小和位置信息,并根據位置關系計算每個子節點在父節點中期望的主輔軸對齊方式和內外邊距。出隊遍歷時,父節點會根據子節點期望的對齊方式確定父節點最終的主輔軸對齊方式,并根據子節點的拉伸意圖修正父節點的大小。拉伸意圖即節點的大小不固定,根據顯示內容不同,在水平或垂直方向上可能會變大或變小,例如文本節點根據顯示字數的多少長度會發生變化,字數過多時甚至還會換行。
2.2.2 屬性信息調整
由于輸入源是基于設計稿呈現的靜態效果圖,設計稿中每個元素缺失了真實的業務含義,同樣的展示效果在不同的業務場景中會有不同的屬性要求,對于這部分內容,我們無法從輸入源中進行準確推斷。為此,我們提供了可視化的屬性信息調整功能來輔助代碼生成,頁面效果如下圖所示,在這個頁面可以對DSL中的所有節點屬性進行查看和修改調整。
經過業務信息補充后,便可進行最后的自動代碼轉化,通過語法映射自動把DSL轉化成MTFlexbox模板代碼。
3 成果展示
下面是設計稿直接生成代碼未經修改展示后的手機屏幕截圖,可以看到取得了不錯的還原效果:
以上就是我們近期對代碼自動生成的探索及實踐,后續我們將引入機器學習及神經網絡算法,對過程進行進一步優化。如果您有其他的看法或建議,也歡迎在文末進行評論,或者跟我們聯系。
作者簡介
田貝、少寬、騰飛等,美團平臺終端業務研發團隊研發工程師。
----------? END? ----------
招聘信息
美團平臺終端業務研發團隊的職責是保障平臺業務高效、穩定迭代的同時,持續優化用戶體驗和研發效率。團隊負責的業務主要包括美團首頁等千萬級DAU高頻業務以及分享、賬號、音/視頻等基礎業務,支撐和對接外賣、酒店等30多個業務方。團隊通過動態化能力建設,加快業務上線速度,幫助產品(PM)快速驗證業務選型,做出業務決策;架構/服務標準化體系建設,提升前后端以及平臺與業務線的溝通、合作效率;業務監控和體驗優化,有效保障核心業務服務成功率的同時,提升用戶使用美團App過程中的穩定性和流暢性。團隊開發技術棧包括Android、iOS、React Native、Flexbox等。
美團平臺終端業務研發團隊是一個活力四射、對技術充滿激情的團隊,現誠聘Android、iOS、FE工程師,歡迎有興趣的同學投簡歷至tech@meituan.com(備注:美團平臺終端業務研發團隊)。
也許你還想看
? |?積木Sketch插件進階開發指南
? |?積木Sketch Plugin:設計同學的貼心搭檔
? |?AI技術在智能海報設計中的應用
總結
以上是生活随笔為你收集整理的设计稿(UI视图)自动生成代码方案的探索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 可见光-反射红外遥感
- 下一篇: 可伸缩性和重/轻量,谁是实用系统的架构主