0x1、引言
2333,看這標題就知道不是什麼正經技術文章,花了點時間,寫了個「無用良品」,以後請叫我「Android界愛迪生——樊少皇」,蟹蟹~
![](https://i.iter01.com/images/56f0cbf3d22a88057f94b41b8a191104864acab3f96853c0dd157b99dab85036.png)
最近公司APP版本迭代,一個人寫介面,寫到我真的想吐:
![](https://i.iter01.com/images/fcf5ceb485e4dee89ef87407b00d251e02d83336d3e9d42b91c2802261d18114.png)
有些路人可能會說:不喜歡寫,你不會拖拉控制元件嗎,憨憨。
![](https://i.iter01.com/images/59e39ab581be149070f9c20f96904b0e9a6314e1c80a604a9744aff5220310c5.png)
可能各位都是:i9 9900K,850 PRO,64G DDR4,拖拽控制元件絲滑流暢,不知人間疾苦…
如果您像小弟一樣用著公司配的:i3家用桌上型電腦,你也會秒變「祖安人」
![](https://i.iter01.com/images/4ccae919da291b4dc80c22d4550b438cf22f8fefcd8d870adfa702bb3da77808.png)
拖拽卡頓不靈活不說,拖拽完還得進程式碼調來調去,有時效率還不如手敲。
Google很久以前出的ConstraintLayout約束佈局是挺好用的,就是要寫多一堆屬性,比如每個控制元件必不可少的:
![](https://i.iter01.com/images/f8bd3b3c2ccb90ba67dbc8436d3ad9a81721b22236e81a0abd577b9a1b6e7aa6.png)
雖說AS自動補全,但是寫起來,效率並不是很高。作為一個「具有4點多堆砌佈局經驗的Android開發仔」一個重要的標準就是:看到一個設計圖,立馬在心中解析出「頁面佈局的層次結構」比如這樣的個人中心的頁面:
![](https://i.iter01.com/images/eb3bda3ccf2ce8bd735e81955b1cc339782eddb18d3ed023835aaf75f9102ef3.png)
直接解析:
約束佈局
相對佈局
回退- Button
標題-TextView
卡片檢視
約束佈局
頭像-ImageView
登陸提示-TextView
更多箭頭-ImageView
卡片檢視
約束佈局
訂單圖示-ImageView
訂單文字-TextView
訂單更多-ImageView
兌換圖示-ImageView
兌換文字-TextView
兌換更多-ImageView
...略
複製程式碼
解析倒是挺簡單,不顧敲起來,大部分是機器式重複,。前不久在逼乎上看到這段話:
![](https://i.iter01.com/images/97095b4edbcaa009bafd7abe282643c4686c9b997966f436e33826d68f447376.png)
覺得還挺有道理,著實需要一種智識和能力去改進,從這樣的「時間泥潭」中跳出。
腦海中萌生了「模板程式碼」思路:
和AS自帶新建佈局模板的方式有點不一樣,精確到控制元件級別,用 關鍵字匹配 控制元件對應的模板程式碼。
![](https://i.iter01.com/images/e61714b01805bed85e68f902ae25cd5b9c366deb3789e86fa8787cbe22c2fa43.png)
當我輸入tv的時候,匯入對應的一大串程式碼,輸入tvc的時候匯入另一串程式碼。
不過這個思路在我寫完一個TextView後就放棄了,TM的那麼多控制元件,要寫多少套,而且很多屬性是多餘的…
![](https://i.iter01.com/images/8e6fce38dc75abba95990b16c7cdeeebb7e0c70306fc11e14cbacc51391ff592.png)
這種思路妥妥滴不行,於是又萌生了另一種思路:
「定義一套自己的語法規則,寫少量,用指令碼翻譯成AS裡的XML檔案」
嘖嘖嘖,這樣也意味著可以
「可以脫離Android Studio寫佈局檔案,而且比一個個字母手敲xml高效!」
想想,你可以「在地鐵上用便籤寫佈局,然後到公司用指令碼直接翻譯成XML佈局」太酷了吧!
![](https://i.iter01.com/images/7b820c691d6c7cfe2e39f2bf93ebcbde76a102fcebd631633a85a367f49d7e51.png)
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用於儲存「自定義簡稱 與 控制元件的對映關係」
![](https://i.iter01.com/images/7605711a98ed7dded96cd0d2164a61100d7e76ca419f92bcfcf039ac49ed6259.png)
注意:這裡的簡稱可以定義成你自己喜歡的,中文也行!
接著寫個讀取配置檔案的指令碼config_getter.py,讀取下:
![](https://i.iter01.com/images/41ba4d4ba8eb9996c14c4c23c6e8008d72379e70caba3d5a37846245d7667819.png)
再接著新建一個輸入源test.txt檔案,內容如下:
![](https://i.iter01.com/images/d326f7f6a542bfafae5dd7d6eded1b35f2efc1dee4b7aa3745f55b1e1c558e3c.png)
最後寫指令碼讀取txt檔案,按行讀取,過濾空格和換行,根據字串第一個字元進行過濾:
![](https://i.iter01.com/images/38227447247da4cdd618ed5e75b24da4475541d53ea13832534f042927de501d.png)
執行後可以看到輸出的xml檔案:
![](https://i.iter01.com/images/2672698f14e3c9d567fc4a215471ab6ceb227d4dfc3c83b2c5e1fe3dec0d2efc.png)
堆一起,看不出什麼,格式化看看效果:
![](https://i.iter01.com/images/b1184ab133a737d6da412a06d5845ad77533ad3e5d210acd714d5d5c95b59daa.png)
嘖嘖嘖,有內味了。
![](https://i.iter01.com/images/2518ca89cc4d30034988f44c9d979b09d0cbd08e9097c57f796dbc1b0e4160f8.png)
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"
![](https://i.iter01.com/images/551386583ff670005ea06f1dbc203ddfe6257146c7a6f8c863afad2e3ff6b88f.png)
程式處理的時候需要對:w-w 和 ww進行區分,區分方法也很簡單:
len(split("-")) == 1,說明是後者,否則是前者
嘖嘖嘖,可以,繼續~
![](https://i.iter01.com/images/2ff0d804863d2362dc3f4588f6c24b07f032d3ebffa8dc68aa4e67c51a92dd10.png)
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: 判斷是否包含此屬性,是填充模板,否則直接填充
也很簡單,接下來就是寫程式碼來組裝我們的「老八祕製小漢堡」了!!!
![](https://i.iter01.com/images/8f7a5c10a6632ec4d6aec83e34f3e6c6960f6caf27dcde69f848543b4a6163d2.png)
0x3、組裝老八祕製小漢堡
先是完善配置檔案:config.ini
![](https://i.iter01.com/images/1938e63c8ddbf4f2e55c1f3110fa5fa3faf4328e454dac947a8fb1d4a32aef3d.png)
這裡可以根據自己的習慣自定義在對應的區域,增加或者減少,動態配置~
在翻譯指令碼 AutoTranslate.py 的開頭讀取一波配置資訊:
![](https://i.iter01.com/images/431051204f6225f1eefee9fcdf9f9c68ca2065d5fa16ae2a995661800fcba8ac.png)
接著定義一個讀取節點列表的方法:
![](https://i.iter01.com/images/b04f018169fde00a5b9dc89fa5f0b8c14f0e9f9b7267bcd3e4c0abf0bd8dafea.png)
再接著定義一個解析翻譯結點內容的方法:
![](https://i.iter01.com/images/4c0ae0d67a918f52c5311839e462c8b69a053af50bb8f9ab844c4301d68f8502.png)
![](https://i.iter01.com/images/3f1c1d5a87e11a587cfa561ece99850bff9c841843e223e837fbe41e53967b73.png)
最後定義一個寫入檔案的方法:
![](https://i.iter01.com/images/f8e8508eedeab402cd8799cb43ceb278a9c9ca7725cbc625e818d47824ec2167.png)
接著花幾分鐘寫個佈局txt檔案:
![](https://i.iter01.com/images/88fc486563449e7c738d3fb1930aaeb8299df28becf4f23021ec3f037fc3ecc7.png)
轉換指令碼呼叫下相關方法:
![](https://i.iter01.com/images/de35033bd779a5f42c060299765ba0988789ae21acd3782eb19486b1627a9cde.png)
執行一波,可以看到生成了一個test.xml的佈局檔案,開啟瞅瞅:
![](https://i.iter01.com/images/e1e97ce5e71cafb07674c379085da1f10ff9f434d172466b0ba63496d72ea92e.png)
嘖嘖,格式化?
![](https://i.iter01.com/images/6b411d3d5b8594c375914e2da439ab08e003b6a0694ecd2f3fce13252d675b00.png)
把xml複製到專案中,看看效果?
![](https://i.iter01.com/images/228887e9349aa2f83f40e3365f9e9339cb0485312a8c59a15002fde28db9a890.png)
此處應該有掌聲!啪啪啪!
![](https://i.iter01.com/images/fd84c87294249bcb61fa68d3056e30ad4aa80adafb6f3d43a832553c049f0482.png)
0x4、奧利給,吃粑粑
指令碼的大概雛形完成了,後面可以優化下互動和小細節,不過感覺沒技術含量?巧了,最近在 刷題,加個演算法耍耍?來個LeetCode原題「有效的括號」,題目描述如下:
![](https://i.iter01.com/images/5eef9bd8362a8070df621cb80da826a97238ae8d39682bf3ac25ce3fa7ec7416.png)
就是 匹配符號開閉,跟我們這個場景非常相似哇,匹配開閉節點:
# 開閉節點需要一一對應,比如:
+ cly
- cly
# 多了少了,都不行(如下兩種都是錯誤的)
+ cly
+ cly
- cly
+ cly
+ ly
- cly
- ly
複製程式碼
怎麼解決?最標準解法就是用 棧 了,比較簡單,直接擼程式碼:
![](https://i.iter01.com/images/6fc8218fc8dd4355b67b847247bf55242551bf1bb27b1e5a94665dd21aab7a58.png)
接著呼叫下:
![](https://i.iter01.com/images/4ac2a1e2c3b7a7e6215ccc229721be6012535a0ddfb69578dfb429ec70243f67.png)
故意寫錯結點,執行看看:
![](https://i.iter01.com/images/9b48ed4e85c6601b19edf45d6f0a760459ac0b5b39c3a188e58412dfbc020d8b.png)
可以,大功告成~
![](https://i.iter01.com/images/651ec4eff4b7627368ac5c8721598a93762ddebb0ca505de30a9daf1ac87b80d.png)
0x5、小結
久違的摸魚閒暇時光,給大家做了一個老八祕製作小?,呸…
「Android佈局翻譯器」
有了它,你可以在??上用文字編輯器,便籤等來完成Android佈局的編寫。
當然,目前只是雛形,你可以根據自己需要,進行動態配置,優化等,以此提高你的效率~
此時我突然想起:曾揚言收購蘋果,如今直播帶貨的老羅,當初提出的TNT系統,結合下這個指令碼,
寫佈局完全可以靠喊:
文字框 > 居中 > 變黑 > 變大 > 加粗…
![](https://i.iter01.com/images/5f270169c4a1480ca991a80c6014ef907520f33825216fccf529dfd3915c7c9f.png)
嘖嘖嘖,有點意思,本節的一本正經的胡說八道到此結束,感謝閱讀~
- Github倉庫:github.com/coder-pig/A…
![](https://i.iter01.com/images/1e7c08f517829f7f53b8faa34cc6ffe24e09c4664030e9d659eab6d1740ccfad.png)