Android 布 局 翻 譯 器

coder-pig發表於2020-03-21

0x1、引言


2333,看這標題就知道不是什麼正經技術文章,花了點時間,寫了個「無用良品」,以後請叫我「Android界愛迪生——樊少皇」,蟹蟹~

最近公司APP版本迭代,一個人寫介面,寫到我真的想吐:

有些路人可能會說:不喜歡寫,你不會拖拉控制元件嗎,憨憨。

可能各位都是:i9 9900K,850 PRO,64G DDR4,拖拽控制元件絲滑流暢,不知人間疾苦…
如果您像小弟一樣用著公司配的:i3家用桌上型電腦,你也會秒變「祖安人

拖拽卡頓不靈活不說,拖拽完還得進程式碼調來調去,有時效率還不如手敲。
Google很久以前出的ConstraintLayout約束佈局是挺好用的,就是要寫多一堆屬性,比如每個控制元件必不可少的:

雖說AS自動補全,但是寫起來,效率並不是很高。作為一個「具有4點多堆砌佈局經驗的Android開發仔」一個重要的標準就是:看到一個設計圖,立馬在心中解析出「頁面佈局的層次結構」比如這樣的個人中心的頁面:

直接解析:

約束佈局
    相對佈局
        回退- Button
        標題-TextView
    卡片檢視
        約束佈局
            頭像-ImageView
            登陸提示-TextView
            更多箭頭-ImageView
    卡片檢視
        約束佈局
            訂單圖示-ImageView
            訂單文字-TextView
            訂單更多-ImageView
            兌換圖示-ImageView
            兌換文字-TextView
            兌換更多-ImageView
...
複製程式碼

解析倒是挺簡單,不顧敲起來,大部分是機器式重複,。前不久在逼乎上看到這段話:

覺得還挺有道理,著實需要一種智識和能力去改進,從這樣的「時間泥潭」中跳出。

腦海中萌生了「模板程式碼」思路:

和AS自帶新建佈局模板的方式有點不一樣,精確到控制元件級別,用 關鍵字匹配 控制元件對應的模板程式碼。

當我輸入tv的時候,匯入對應的一大串程式碼,輸入tvc的時候匯入另一串程式碼。
不過這個思路在我寫完一個TextView後就放棄了,TM的那麼多控制元件,要寫多少套,而且很多屬性是多餘的…

這種思路妥妥滴不行,於是又萌生了另一種思路:

定義一套自己的語法規則,寫少量,用指令碼翻譯成AS裡的XML檔案

嘖嘖嘖,這樣也意味著可以

可以脫離Android Studio寫佈局檔案,而且比一個個字母手敲xml高效!

想想,你可以「在地鐵上用便籤寫佈局,然後到公司用指令碼直接翻譯成XML佈局」太酷了吧!


0x2、規律 => 規則


定義這套語法規則之前,我們先要了解一下xml佈局的規律:

# XML由一個個標籤(結點)構成,分為:單標籤 和 雙標籤(可巢狀),如:
<TextView .../> 和 <LinearLayout ..></LinearLayout> 

# 然後標籤的組成
<控制元件名 
    屬性:
    屬性:值 
    .../>

複製程式碼

綜上,不難得出兩個規律:

① 標籤其實有三種:開標籤關標籤閉合標籤,要進行區分
② 標籤 = <控制元件名 若干屬性:值>

另外,Android是建議,每個控制元件都設定一個id屬性的,不難定義一個類來代表一個標籤:

class Node:
    def __init__(self, widget=None, id=None, kv=None):
        self.widget = widget
        self.id = id
        self.kv = kv
複製程式碼

1、標籤的區分


上面也說了,標籤由三種,這裡引入三個符號來進行標記(+-*),比如:

+ 線性佈局
    * 文字檢視
- 線性佈局
複製程式碼

新建配置檔案config.ini用於儲存「自定義簡稱控制元件的對映關係

注意這裡的簡稱可以定義成你自己喜歡的,中文也行
接著寫個讀取配置檔案的指令碼config_getter.py,讀取下:

再接著新建一個輸入源test.txt檔案,內容如下:

最後寫指令碼讀取txt檔案,按行讀取,過濾空格和換行根據字串第一個字元進行過濾

執行後可以看到輸出的xml檔案:

堆一起,看不出什麼,格式化看看效果:

嘖嘖嘖,有內味了。


2、屬性


一個控制元件可以有多個屬性,多個屬性怎麼進行分割呢?筆者用的是「>
然後屬性和值又怎麼分割呢?本來是想用 :或| 的,後面發現都用到了,最後決定用「-」來分割。
一個簡單的示例如下:

bt > bt_back > w-56 > h-56 > t-返回 
複製程式碼

上述的程式碼代表:

定義一個按鈕,id為bt_back,寬56dp,高56dp,文字為返回

另外,有些常用的屬性-值,可以簡化下,比如:

android:layout_width="wrap_content"

# 可以寫成
w-wrap_content

# 簡化
w-w

# 再簡化
ww
複製程式碼

ww 就可以代替:android:layout_width="wrap_content"

程式處理的時候需要對:w-w 和 ww進行區分,區分方法也很簡單:

len(split("-")) == 1,說明是後者,否則是前者

嘖嘖嘖,可以,繼續~


3、值


值的情形稍微複雜一點,常見的有下面這些:

android:gravity="center|start"
android:layout_width="match_parent"
android:background="@drawable/ic_back_white"
android:layout_marginStart="60dp"
app:layout_constraintDimensionRatio="16:9"
複製程式碼

其實劃分下,筆者需要只需區分三種型別

  • ① 直接填充 -> 屬性="xxx"
  • ② 數字dp -> 屬性="xdp"
  • ③ @資源引用 -> 屬性="@x/y"

所以處理的流程:

Step 1:判斷是否為數字,是的話加上dp,否則跳Step 2
Step 2:利用正則判斷是否為@型別,是的話提取下型別與值,否則跳Step3
Step 3: 判斷是否包含此屬性,是填充模板,否則直接填充

也很簡單,接下來就是寫程式碼來組裝我們的「老八祕製小漢堡」了!!!


0x3、組裝老八祕製小漢堡


先是完善配置檔案:config.ini

這裡可以根據自己的習慣自定義在對應的區域,增加或者減少,動態配置~
在翻譯指令碼 AutoTranslate.py 的開頭讀取一波配置資訊:

接著定義一個讀取節點列表的方法:

再接著定義一個解析翻譯結點內容的方法:


最後定義一個寫入檔案的方法:

接著花幾分鐘寫個佈局txt檔案:

轉換指令碼呼叫下相關方法:

執行一波,可以看到生成了一個test.xml的佈局檔案,開啟瞅瞅:

嘖嘖,格式化?

把xml複製到專案中,看看效果?

此處應該有掌聲!啪啪啪!


0x4、奧利給,吃粑粑


指令碼的大概雛形完成了,後面可以優化下互動和小細節,不過感覺沒技術含量?巧了,最近在 刷題,加個演算法耍耍?來個LeetCode原題有效的括號,題目描述如下:

就是 匹配符號開閉,跟我們這個場景非常相似哇,匹配開閉節點

# 開閉節點需要一一對應,比如:
cly
cly

# 多了少了,都不行(如下兩種都是錯誤的)
cly
cly
cly

cly
ly
cly
ly
複製程式碼

怎麼解決?最標準解法就是用 了,比較簡單,直接擼程式碼:

接著呼叫下:

故意寫錯結點,執行看看:

可以,大功告成~


0x5、小結


久違的摸魚閒暇時光,給大家做了一個老八祕製作小?,呸…

Android佈局翻譯器

有了它,你可以在??上用文字編輯器,便籤等來完成Android佈局的編寫。
當然,目前只是雛形,你可以根據自己需要,進行動態配置,優化等,以此提高你的效率~
此時我突然想起:曾揚言收購蘋果,如今直播帶貨的老羅,當初提出的TNT系統,結合下這個指令碼,
寫佈局完全可以靠喊:

文字框 > 居中 > 變黑 > 變大 > 加粗…

嘖嘖嘖,有點意思,本節的一本正經的胡說八道到此結束,感謝閱讀~




相關文章