Android自動生成Shape資原始檔(下)

語言: CN / TW / HK

highlight: a11y-dark

系列文章目錄

| 索引 | 標題 | | --- | --- | |第一章|Android自動生成程式碼,視覺化腳手架,將大大提高開發效率| |第二章|Android自動生成程式碼,視覺化腳手架之環境搭建| |第三章|Android自動生成程式碼,視覺化腳手架之基礎資訊配置| |第四章|Android自動生成Shape資原始檔,邁出視覺化腳手架第一步!(上)|

系列文章Github開源地址(原始碼及各項資料不間斷進行更新):

https://github.com/AbnerMing888/AndroidShortcutTools

上半部分,我們已經實現了視覺化的基本資訊配置,也就是視覺化的第一個頁面,這僅僅是一個前奏,在第一章裡,我已經羅列了很多的功能,所以啊老鐵們,抽個時間一定要去前邊看一看,因為很多人的問題,我基本上前邊都已經給出瞭解答,比如為什麼不採用Android studio裡的外掛實現,工具在哪下載等等,都訴說的很清楚,這裡就不一一贅述了,我們繼續上半部分陳述。

針對Shape的實現,是視覺化腳手架裡最簡單的,因為沒有什麼邏輯可言,都是現成的模板,無非就是改裡面的屬性而已,老鐵們,記住啊,視覺化說到底,確實沒有什麼技術含量,大多都是動態的更改,比如這個Shape,在正常的開發中,無非就是,實心的,空心的,漸變的,左上右下帶角度的,那麼針對常見的幾種方式,我們做好模板,然後根據你在視覺化工具的選擇,動態的進行改變即可。

細節的原始碼,大家可以直接去GitHub上下載瀏覽,文章裡就不過多的贅述,我們主要說下具體的實現方式。

一、頁面繪製及儲存到drawable資料夾下。

視覺化的工具,之前說過,採用的是Web開發,相對於Android而言,還是比較簡單的,無非就是各個標籤的羅列,針對這個最終效果,畢竟我也不是搞Web開發的,也沒有一個UI設計,所有的效果都是自己根據實際業務而來的,醜是醜了點,大家可以將就著看哈。

具體的頁面,大家可以看原始碼中的shape.html這個檔案,都是div標籤,就不貼了,沒啥好說的。

image.png

選擇對應生成資料夾,這個功能是在你選擇專案或者一個資料夾的時候,下面有很多的子目錄,或者說直接是Module,這種情況下,你就可以進行選擇生成到哪個Module下,這個選擇是根據基礎配置裡的選擇路徑而來的,所以啊,基礎配置選擇專案生成路徑,大家儘量選擇一個Android專案。選擇生成到哪個Module下之後,就會自動在儲存在對應的res下的drawable資料夾下。

如何根據選擇的Android專案,儲存到對應的drawable下呢?這個就很簡單了,專案路徑(基礎配置頁面選擇的路徑)加上當前頁面選擇的生成資料夾路徑,就可以很好的知道對應的drawable路徑了。

image.png

每個module下的drawable是固定的,無非在上邊的兩個路徑下,拼接後邊的drawable路徑即可。

如下圖程式碼,selectPath是基礎配置頁面裡選擇的專案路徑,selectFile是你選擇的路徑,後邊拼接固定的 /src/main/res即可,再後面就是shape檔案資源的名字了。

image.png

有一個需要注意的點是,drawable資料夾可能不在,那麼你就要判斷drawable是否存在了,存在就執行寫入,不存在,就先建立drawable資料夾,然後在執行寫入,這個寫入就是,寫入生成shape的程式碼,後面會說到。

```js //先判斷drawable檔案是否存在,不存在去建立

fs.readdir(endPathFile, function (err, files) {

if (err) {         return;     }

var booDrawable = false;

files.forEach(function (item) {

if ("drawable" === item) {             booDrawable = true;         }

});

//存在     if (booDrawable) {         writeDrawable(endPath, endShapeText);     } else {         //不存在,建立         fs.mkdir(endPathFile + "/drawable", function (err) {

if (err) {                 return;             }             writeDrawable(endPath, endShapeText);

});

}

}); ``` 還有一個問題需要注意,雖然我們說了,一定要選擇Android專案,我相信,肯定有很多小老弟,就不選擇Android專案,那麼在不是Android專案的前提下,就不能執行同樣的邏輯了,需要特殊處理,畢竟不是Android專案的路徑,src,res的資料夾可能都不存在,所以,針對這個特殊情況,我們要提前的判斷了。

我是這樣判斷的,當然大家如果有好的判斷方式,也可以積極的共享哈,首先,拿到使用者選擇的專案路徑,也就是基礎配置頁面選擇的路徑,然後進行遍歷,遍歷的時候當出現Android標識性檔案的時候,我用個變數做個累加,比如出現,app資料夾,gradle.properties檔案,build.gradle檔案等,當定義的變數累計到定義的標識後,就認為選擇的是一個Android專案。

js //檢測選擇的是否是一個Android專案,通過是否包含app,gradle,settings.gradle,當然也可以判斷其他 if (item === "app" || item === "gradle" || item === "settings.gradle") {     numAndroid++; } 是Android專案就可以生成到對應的drawable下,否則就普通資料夾下,具體可以看原始碼示例。

一、根據對應模板程式碼和UI檢視選擇,生成對應的資源

模板是固定的,唯一改變的就是裡面的屬性,比如下圖,無非就是radius和color裡屬性需要改,其他的都是固定的,需要改的就要繪製相關的UI檢視了。

image.png

目前的UI檢視,很簡單,無非就是三個功能,實心,空心,和漸變,當然了,這是我定義的,如果你還有拓展的功能,可以自己在原始碼中自己拓展。

image.png

根據這三個功能,我們定義好固定的三個模板,根據檢視中相關選擇,動態改變即可。

實心模板,注意看相關注釋。

image.png

實現程式碼,需要注意,這裡我在檢視中,定義了左上,右上,左下,右下,四個選擇框,就是對應程式碼裡左上右下相關的角度,依次對應的點選記錄為,0,1,2,3。

```js //獲取實心的程式碼 function getSolidText(radius, color, checkText) {     var content = "<?xml version="1.0" encoding="utf-8"?>\n" +         "\n";     //不為空     if (radius != "" && radius != null && selectDp != null && selectDp != "") {         //取出預設的dp配置字首         radius = selectDp + radius;     } else {         radius = (radius == null || radius === "") ? "" : radius + "dp";     }

if (radius != null && (checkText == "" || checkText == "0123")) {         //全部         content = content + "    \n";     } else {

content = content + "    <corners\n";

if (checkText.indexOf("0") != -1) {

content = content + "        android:topLeftRadius="" + radius + ""\n";         }

if (checkText.indexOf("1") != -1) {

content = content + "        android:topRightRadius="" + radius + ""\n";         }

if (checkText.indexOf("2") != -1) {             content = content + "        android:bottomLeftRadius="" + radius + ""\n";         }

if (checkText.indexOf("3") != -1) {             content = content + "        android:bottomRightRadius="" + radius + ""\n";         }         content = content + "        />\n";     }

//基礎資訊color不為空,就追加字首     color = getEndColor(color);     content = content + "    \n";     content = content + "";     return content; } ``` 空心(帶有邊框的shape)模板

和實心的區別就是,加了一個邊框,其他的都沒怎麼變。

image.png

程式碼實現:

```js //獲取空心也就是帶有邊框的程式碼 function getStrokeText(radius, solid, react, reactSize, checkText) {

//不為空     if (radius != "" && radius != null && selectDp != null && selectDp != "") {         //取出預設的dp配置字首         radius = selectDp + radius;     } else {         radius = radius + "dp";     }

if (reactSize != "" && reactSize != null && selectDp != null && selectDp != "") {         //取出預設的dp配置字首         reactSize = selectDp + reactSize;     } else {         reactSize = reactSize + "dp";     }

//邊框顏色     //基礎資訊color不為空,就追加字首     react = getEndColor(react);

var content = "<?xml version="1.0" encoding="utf-8"?>\n" +

"<shape xmlns:android="http://schemas.android.com/apk/res/android"\n" +

"    >\n";

content = content + "    <stroke\n" +

"        android:width="" + reactSize + ""\n" +

"        android:color="" + react + "" />\n";

if (radius != null && (checkText == "" || checkText == "0123")) {         //全部         content = content + "    \n";     } else {         content = content + "    <corners \n";         if (checkText.indexOf("0") != -1) {             content = content + "android:topLeftRadius="" + radius + ""\n";         }

if (checkText.indexOf("1") != -1) {             content = content + "        android:topRightRadius="" + radius + ""\n";         }

if (checkText.indexOf("2") != -1) {             content = content + "        android:bottomLeftRadius="" + radius + ""\n";         }

if (checkText.indexOf("3") != -1) {             content = content + "        android:bottomRightRadius="" + radius + ""\n";         }         content = content + "        />\n";

}     solid = getEndColor(solid);     content = content + " \n";     content = content + ""     return content;

} ``` 漸變模板:

image.png

程式碼實現:

```js //獲取漸變 function getGradientXml(radius, checkText) {     //漸變     var inputReactStartColor = $(".input_react_start_color").val();//起始顏色     var inputReactCenterColor = $(".input_react_center_color").val();//中間顏色     var inputReactEndColor = $(".input_react_end_color").val();//結束顏色     let inputReactGradientRadius = $(".input_react_gradient_radius").val();//漸變角度     let shapeGradientType = $("input[name='shapeGradientType']:checked").val();

inputReactStartColor = getEndColor(inputReactStartColor);     inputReactCenterColor = getEndColor(inputReactCenterColor);     inputReactEndColor = getEndColor(inputReactEndColor);

if (inputReactGradientRadius == null || inputReactGradientRadius == "") {         showToast("請輸入漸變角度");         return "";     }

var sgType;     if (shapeGradientType == 0) {         sgType = "linear";     } else if (shapeGradientType == 1) {         sgType = "radial";     } else {         sgType = "sweep";     }

var gradient = "<?xml version="1.0" encoding="utf-8"?>\n" +

"\n" +

"\n" +

"    <gradient\n" +

"        android:angle="" + inputReactGradientRadius + ""\n";

if (inputReactCenterColor != null && inputReactCenterColor != "") {

gradient = gradient + "        android:centerColor="" + inputReactCenterColor + ""\n";

}

gradient = gradient + "        android:endColor="" + inputReactEndColor + ""\n" +

"        android:startColor="" + inputReactStartColor + ""\n" +

"        android:type="" + sgType + "" />\n"

//不為空

if (radius != "" && radius != null) {

//取出預設配置字首,若不為空,就追加

if (selectDp != "" && selectDp != null) {             radius = selectDp + radius;         } else {             radius = radius + "dp";         }

if (checkText == "" || checkText == "0123") {             //全部             gradient = gradient + "    \n";

} else {             gradient = gradient + "    <corners\n";             if (checkText.indexOf("0") != -1) {                 gradient = gradient + "        android:topLeftRadius="" + radius + ""\n";             }             if (checkText.indexOf("1") != -1) {                 gradient = gradient + "        android:topRightRadius="" + radius + ""\n";             }

if (checkText.indexOf("2") != -1) {                 gradient = gradient + "        android:bottomLeftRadius="" + radius + ""\n";             }

if (checkText.indexOf("3") != -1) {                 gradient = gradient + "        android:bottomRightRadius="" + radius + ""\n";             }

gradient = gradient + "        />\n";

}

}

gradient = gradient + "";     return gradient;

} ``` 當然了具體邏輯相關的,大家可以檢視原始碼,有任何問題,也可以留言諮詢。

選擇顏色這塊用到了一個三方,也放到原始碼裡面了,方便大家進行取色,UI圖裡特意設定了一個名字,因為shape資源生成有一定的規範用名,特別是在元件化開發的專案,所以簡單的設定了一下規範用名,可以一鍵獲取,根據你設定的顏色,角度來進行填充。

Shape的視覺化生成就是如此的簡單,好了各位老鐵,下一篇,我們搞一個視覺化的多渠道打包,一秒可生成N個渠道包,敬請期待!

image.png