日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UI2Code智能生成Flutter代码——机器生成代码

發布時間:2024/8/23 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UI2Code智能生成Flutter代码——机器生成代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

在《UI2CODE--整體設計》篇中,我們提到UI2Code工程的整體流程。前步圖片分析之后,我們可以得到對應的DSL布局描述。利用DSL的資訊,結合IntelliJ Plugin介面工具,面向使用者提供生成對應Flutter代碼。

本篇主要介紹我們如何處理DSL的資訊,想法上即是Flutter的翻譯機。總體概念如下:

輸入的DSL是什么?

DSL做為一種描述語言,抽象表示為了解決某一類任務而專門設計的計算機語言。在此我們的DSL代表圖像識別和布局識別側的輸出,為一JSON格式。

這些資訊主要描述了這個圖層(Layer)的范圍(Frame)、是什么樣子的類型(Type)、是什么樣子的樣式(Styles)、含有哪些數據(Value)等等。圖層集(Layers)欄位則代表了這張視覺稿的所有圖層。

核心思路

本節的目標是將DSL翻譯成目標的Flutter代碼。我們首先需要理解的是分散的圖層間的關系,可能會有交疊、可能是并列排版。知道了關系之后,需想辦法轉化成Flutter widget的視圖,根據此視圖來生產對應代碼。

架構上我們把DSL tree和Flutter tree的建立,分拆為兩個獨立的分界。這樣比較容易定義問題,并且保持彈性。如果今天的目標語言換成Weex或是iOS UI,我們就只需要更動代碼翻譯的模組。

第一把刀:DSL tree建立

上圖的左側代表了來源DSL的layers資料,代表者一個一個的圖層。右側是目標的DSL Tree,這棵樹的結構上明確敘述了圖層之間的包裹、交疊等關系。并且包含了某些特殊關系的節點聚合。

作法上利用每個Layer的Frame,以及所屬的類別(文字、圖像、容器),利用下面的規則組合樹的關系:

  • 圖層之間的包裹關系,例如某些圖層為容器,代表下面是可以掛其他節點的(這邊帶有背景屬性的容器,我們定義稱之為Shape
  • 區塊式組件(Block, 如ListView/GridView)。可以將圖層組成View item的關系
  • 閑魚定義的組件資訊(如CI以及BI),這部份非閑魚工程可以忽略
  • 重復布局(Repeat)的資訊,將相同的圖層歸類合并,目的為簡化樹
  • 根據以上我們采用了分層,由大至小的次序將Layer分群合并。另外,在合并時layer之間彼此可能有關聯;它們可能同屬于Block,也可能同屬于某個Repeat。所以對于上面定義的Repeat、BI、Block、CI、Shape都可能有交錯的嵌套關系,這是必須要處理的部份。

    第二把刀:Flutter tree建立

    在Flutter Tree的建構中,核心概念先處理布局。布局的概念如剝洋蔥一般,我們先去除四周的padding,然后以人類視覺layout的直覺先嘗試橫切分,再進行豎切分

    1.先剝洋蔥去除padding

    2.接著我們的算法會先嘗試是否可以橫切,如下圖我們可以切割成為Row1/ Row2

    3.針對Row1在嘗試再進行豎切,如下圖可以得到Column1/ Column2/ Column3

    根據以上切分的規則,我們就可以定義出如Row、Column、Padding的幾個節點,以及它們的Parent/ Child關系。將DSL tree同一層的節點做切分,一邊切分一邊建立Flutter node,遍歷完整顆DSL,即可得到粗略的Flutter tree關系。

    = 無法切分時的處理

    當圖層切分不開時,這時候就要使用絕對布局疊層的概念,這個概念在Flutter內稱之為Stack。

    多個圖層在DSL tree的關系為兄弟節點,根據此些圖層的Frame,我們判斷出來它們是彼此相交的,我們會以Z-order概念,來決定上下交疊的關系。最后,這些圖層將組成一個新Stack節點,并且產生此節點的Frames為此些圖層覆蓋的范圍。

    = 針對文字的進階處理

    基本上交疊的圖層以Stack的處理就可以正確顯示,但在文字圖層上可能含有誤區。

    如上圖因為文字本身的上下左右是含有padding的,在我們圖層的識別時,可能會計算出彼此的frame是交疊的,但實際上UI希望它們并不是Stack關系。

    ?

    為了解決這個問題,我們引入了一個oriFrame的概念,用文字最原始的像素當做是oriFrame。所以遇到為文字的圖層時,我們會先判斷本身的oriFrame是否交疊,如果是的話才采用Stack切割,否則就以此oriFrame對原始的frame做修正。

    文字還有什么特性?

    另外,因為文字的內容通常是動態的,所以擁有了”所見不一定為所得”的特性。這些特性主要包含了是否該換行、內容區域是否可以拉伸、文字Padding等,這些特性都會影響到我們的布局。

    以下圖為例,我們在處理Layout時肉眼很明顯可以知道這些特徵。文字的行數我們可以以視覺稿當做最大顯示范本,文字區域的寬度部分,則需要特別判斷哪些區域是可以被拉伸的。

    確立文字范圍

    在決定拉伸對象之前,我們需要定義哪些widget是將內容完整顯示,不能被拉伸的:如圖片、Container容器、Stack區域、Component組件

    接著處理的流程如下:

  • 首先判斷所有Child內是否有多行文字或寬度固定的文字,如果是的話針對其處理。需要加上Flex。
  • 若無以上的狀況,則判斷Child間的Padding關系
  • 如果可拉伸的widget的Padding大于平均值的個數有多個,則這些都加上Flex
  • 如果只有單個時,則找尋最大Padding的widget(使用分群拉伸算法)
  • 最后,但當Row里面存有拉伸的狀況時,需要把Row的最后一個child加上Right padding,否則拉伸元素會填滿父容器。
  • 分群拉伸算法:這個算法的目的是找到最佳拉伸的對象。我們的思考上將Widget做分組,分組后判斷整體的Alignment(如左右對齊)或是拉伸關系。若在拉伸狀況下,判斷適合讓哪個組別拉伸,在進一步判斷適合讓組別的內部元件拉伸。

    舉例如下為一個Row排列的控件,其中排列為Image、CI、Text1、Text2、Text3:

    依據Widget之間的距離,在上圖分為了Group1及Group2兩個群體。先以Group1判斷是否存在可拉伸的對象, 接著才判斷Group2。所以這5個Widget分別得到了3, 2, 1, 4, 5的優先級。以本例而言,Text1為最高優先,而且其為可拉伸的,故決定將Flex屬性加于此。

    在Expanded的處理上,是我們目前遇到最大的困難點,甚至人工判斷都可能有歧義。上面的規則是我們歸納出眾多視覺稿的通解,但不能100%完全解決問題。所以這部份判斷錯誤的部分,我們期待在Plugin的交互中使用人工解決。

    = 判斷Alignment優化

    以上的處理已經可以正確生成Flutter tree,但是我們想進一步地將Flutter代碼更加優雅。在此我們針對了三種元件的Alignment做了處理,分別是Container、Row、Column,其概念都是分析內部元件的padding關系,決定為居左、居中、或是居右對齊。

    舉例如Column內部的children我們去判斷左右的padding是否相等。若是則移除其padding,并且加上crossAxisAlignment為center。

    針對Row/ Container我們則會判斷crossAxisAlignment(垂直方向)以及mainAxisAlignment(水平方向)。水平部份,這邊我們采用更精細的方法,我們利用歐式距離建立一個非監督算法,計算views是更為接近哪一個(居左、居中、居右)。算法這邊先不詳述,之后再以篇幅介紹。

    最后:生成Flutter代碼

    經過前面的步驟后,最終我們產生了一個Flutter Tree。生成時在節點的定義上,我們分為了兩種,分別是View與Layout,以是否可以擁有Child為區別。以下是我們針對Flutter Tree所定義的部份類別:

    在節點的定義中,皆存儲了各節點的Parent、Child屬性。根據這些關系,我們定義每個節點的代碼樣板,例如FColumn對應的樣板為:

    ?

    new Column( #{alignment}, children: <Widget>[#{children}, ]

    ),?

    最后我們以Root widget開始遍歷整顆樹,將每個節點所生成的Flutter代碼結合,這樣我們就可以得到整個Widget tree的代碼了。

    數據分離

    為了更好的重復利用生成代碼,我們把生成的代碼和數據再進一步做分離。分離后輸出分為代碼區以及Data model數據區:

    我們切割這些區域的目的為簡化Widget tree直觀上的代碼復雜度,以及將數據抽離,讓資料可由外部呼叫傳入,以達成動態性。

    整體架構回顧

    總合以上的概念,工程的細部架構如下:

    前面所說的針對文字以及Alignment的處理,在這邊我們設計了一個工廠模式,如上圖中經過Flutter Tree Builder后,我們可以去遍歷整顆Widget tree,在工廠中判斷判斷符合條件的規則,經過處理去震蕩優化原本的Widget tree。在這邊未來我們可以不斷地加上合適的規則,讓Widget tree更加優化。

    整體架構使用靜態分析的方法,讀到此各位可能會有疑問:一些如動態的事件、View的Visibility、Input輸入文字框等怎么處理?由于這些動態性在靜態分析下無法解決,所以我們增強了Plugin上的編輯性,使用者只要勾選某些屬性,即會在生成代碼時自動判斷,在Flutter自動增加對應的邏輯。以彌補靜態圖無法處理的問題。

    由于UI的靈活性高,十個人寫的代碼可能有十種不同風格。并且在分析上游的UI2DSL,以及Flutter代碼的翻譯,某些部份的精確性取決于我們的樣本的認知,是否能夠在有限的樣本內觀查出泛化的定律,分析上還是存有很多挑戰性。

    結合落地業務

    在整個UI2CODE的效果中,大約七成以上的頁面都可以正確分析出來,剩下的是一些小細節如文字的處理等,基本上我們工具都能夠將大框架的處理好,使用者可能只需微小的調整。

    UI2CODE案子在內部團隊上線后,已經在閑魚APP內的"玩家頁面"采用了自動化生成的代碼。在采用自動化工具后,大約減少了三分之二的UI開發時間(因初期還在熟悉工作流程,未來相信可以更快速)。同時,若在客戶端大量采用我們工具,還可以讓團隊的代碼結構有一些的規范,讓生成工具來規范Widget UI以及Data Binding的框架,一致性以及后續的維護,相信是一個很大的誘因。

    并且閑魚團隊近期計畫開發一款新的APP,在初期時能夠快速開發UI,也將采用我們的工具。期望有更多的業務和經驗積累。

    后續計畫

    近期我們推出了第一版UI2CODE,先計畫于內部團隊使用,利用使用的經驗,讓我們在疊代之下不斷提高準確性。并且,我們正在調研結合NLP以及AST(語法樹)的可能性,希望能夠產出更有質量的代碼。

    我們也期望未來能將此工具開放于Flutter community,對于推動整個Flutter技術有所推進。希望能讓更多人跟我們一起找尋更有效率的寫代碼方法,如果有任何想法歡迎與我們交流,我們也持續不斷地在進化工具中,謝謝各位的閱讀!


    原文鏈接
    本文為云棲社區原創內容,未經允許不得轉載。

    總結

    以上是生活随笔為你收集整理的UI2Code智能生成Flutter代码——机器生成代码的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。