零、前言:
1.RecyclerView的Adapter自動生成器(含ViewHolder)
2.自定義屬性的自定義View程式碼生成器(含自定義屬性的初始化)
3.svg圖示轉換為Android可用xml生成器
最近喜歡切割字串,這三個類是近期的作品,感覺挺好用的,在此分享一下
三個工具都會貼在本文末尾,本文末尾,本文末尾
一、RecyclerView的Adapter自動生成器(含ViewHolder)
最近寫了幾個RecyclerView的Adapter,控制元件一多ViewHolder寫起來感覺挺不爽的
也感覺其中也只是佈局檔案裡的幾個id和View的型別有區別,寫個工具讀一下xml自動生成一下唄
既然ViewHolder自動生成了,順便吧Adapter也一起生成算了,反正初始也就那一大段
演示一下:
1.把工具類拷貝到test包裡
2.寫上你xml的路徑和生成的.java所在的包
3.點選執行,就可以生成了。如果有問題,歡迎指出
Xml程式碼
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
android:id="@+id/id_cl_root"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="70dp"
tools:context=".MainActivity">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:id="@+id/id_iv_icon"
android:src="@mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/id_tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:maxLines="1"
android:text="name"
android:textColor="#000000"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@id/id_iv_info"
app:layout_constraintStart_toEndOf="@id/id_iv_icon"
app:layout_constraintTop_toTopOf="@id/id_iv_icon"/>
<TextView
android:id="@+id/id_iv_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:ellipsize="end"
android:maxLines="2"
android:text="infoinfoinfoinfo"
android:textColor="@color/qq_line"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/guide_v_95"
app:layout_constraintStart_toEndOf="@id/id_iv_icon"
app:layout_constraintTop_toBottomOf="@id/id_tv_name"/>
<android.support.constraint.Guideline
android:id="@+id/guide_v_95"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.95"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
自動生成的Adapter
點一下,就生成這麼多,一個一個敲怎麼也要五分鐘吧,這種枯燥的工作,還是留給計算機吧。
之後根據自己的業務需求,小修補一下就行了。
附加贈送:findViewById自動生成,控制檯裡,拷貝即用
雖然喜歡用butterknife,但感覺每次加依賴好麻煩,也就是想找個id,也沒必要引個庫,畢竟都佔空間的。
二、自定義屬性的自定義View程式碼生成器(含自定義屬性的初始化)
這可謂我的得意之作,本人比較喜歡自定義控制元件,但自定義屬相寫起來費心費力,也沒什麼含量
基本上也就那麼幾個屬性在變,一咬牙,寫個工具類吧,然後就有了下文:
演示一下使用:
1.把工具類拷貝到test包裡
2.寫上你xml的路徑和生成的.java所在的包,寫上你的專屬字首
3.點選執行,就可以生成了。如果有問題,歡迎指出
注意點
:自定義屬性必須有自己的專屬字首(任意字元都可以,統一即可)
attrs.xml檔案:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TolyProgressBar">
<attr name="z_pb_bg_color" format="color"/>
<attr name="z_pb_bg_height" format="dimension"/>
<attr name="z_pb_on_color" format="color"/>
<attr name="z_pb_on_height" format="dimension"/>
<attr name="z_pb_txt_color" format="color"/>
<attr name="z_pb_txt_size" format="dimension"/>
<attr name="z_pb_txt_offset" format="dimension"/>
<attr name="z_pb_txt_gone" format="boolean"/>
</declare-styleable>
</resources>
複製程式碼
3.svg圖示轉換為Android可用xml生成器
和上面一樣,將所有svg放在一個資料夾裡,即可批處理
附錄
1:Xml2Adapter.java
/**
* 作者:張風捷特烈
* 時間:2018/10/31 0031:8:47
* 郵箱:1981462002@qq.com
* 說明:初始化RecyclerView的Adapter
*/
public class Xml2Adapter {
@Test
public void main() {
//你的佈局xml所在路徑
File file = new File("I:\\Java\\Android\\APL\\VVI_MDs\\test\\src\\main\\res\\layout\\item_goods_list.xml");
//你的Adapter的java類放在哪個包裡
File out = new File("I:\\Java\\Android\\APL\\VVI_MDs\\app\\src\\main\\java\\com\\toly1994\\vvi_mds\\pkg_08_other\\adapter");
//你的Adapter的名字--不要加.java
String name = "GoodsAdapter";
initView(file, out, name);
}
@Test
public void findView() {
//你的佈局xml所在路徑
File file = new File("I:\\Java\\Android\\Unit\\B\\asyn\\src\\main\\res\\layout\\item_list_pic.xml");
findViewById(file);
}
private void findViewById(File in) {
String res = readFile(in);
HashMap<String, String> map = split(res);
StringBuilder sb = new StringBuilder();
map.forEach((id, view) -> {
sb.append("public ").append(view).append(" ").append(formatId2Field(id)).append(";").append("\r\n");
});
sb.append("\n\n");
map.forEach((id, view) -> {
sb.append(formatId2Field(id))
.append("= itemView.findViewById(R.id.")
.append(id).append(");").append("\r\n");
if ("Button".equals(view)) {
sb.append(formatId2Field(id) + ".setOnClickListener(v -> {\n" +
" });\n");
}
});
System.out.println(sb.toString());
}
/**
* 讀取檔案
*
* @param in xml檔案路徑
* @param out 輸出的java路徑
* @param name
*/
private static void initView(File in, File out, String name) {
FileWriter fw = null;
try {
HashMap<String, String> map = split(readFile(in));
String result = contactAdapter(in, out, name, map);
//寫出到磁碟
File outFile = new File(out, name + ".java");
fw = new FileWriter(outFile);
fw.write(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 讀取檔案
*
* @param in
* @return
*/
private static String readFile(File in) {
if (!in.exists() && in.isDirectory()) {
return "";
}
FileReader fr = null;
try {
fr = new FileReader(in);
//字元陣列迴圈讀取
char[] buf = new char[1024];
int len = 0;
StringBuilder sb = new StringBuilder();
while ((len = fr.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return "";
} finally {
try {
if (fr != null) {
fr.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 直接拼接出Adapter
*/
private static String contactAdapter(File file, File out, String name, HashMap<String, String> map) {
StringBuilder sb = new StringBuilder();
String path = out.getAbsolutePath();
path.split("java");
sb.append("package " + path.split("java\\\\")[1].replaceAll("\\\\", ".") + ";\n");
sb.append("import android.content.Context;\n" +
"import android.support.annotation.NonNull;\n" +
"import android.support.constraint.ConstraintLayout;\n" +
"import android.support.v7.widget.RecyclerView;\n" +
"import android.view.LayoutInflater;\n" +
"import android.view.View;\n" +
"import android.view.ViewGroup;\n" +
"import android.widget.Button;\n" +
"import java.util.List;\n" +
"import android.widget.TextView;\n");
sb.append("public class " + name + " extends RecyclerView.Adapter<" + name + ".MyViewHolder> {\n");
sb.append("private Context mContext;\n");
sb.append("private List<String> mData;\n");
sb.append("public " + name + "(List<String> data) {\n" +
" mData = data;\n" +
"}");
String layoutId = file.getName().substring(0, file.getName().indexOf(".x"));
sb.append("@NonNull\n" +
"@Override\n" +
"public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n" +
"mContext = parent.getContext();\n" +
" View view = LayoutInflater.from(mContext).inflate(R.layout." + layoutId + ", parent, false);\n" +
" return new MyViewHolder(view);\n" +
"}\n");
sb.append("@Override \n" +
"public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {\n" +
"String str = mData.get(position);"
);
map.forEach((id, view) -> {
if (view.contains("\n")) {
view = view.split("\n")[0];
}
if ("Button".equals(view)) {
sb.append("holder." + formatId2Field(id) + ".setOnClickListener(v -> {\n" +
" });\n");
}
if ("TextView".equals(view)) {
sb.append("holder." + formatId2Field(id) + ".setText(str);\n");
}
if ("ImageView".equals(view)) {
sb.append("holder." + formatId2Field(id) + ".setImageBitmap(null);\n");
}
});
sb.append("}\n" +
"@Override\n" +
"public int getItemCount() {\n" +
"return mData.size();\n" +
"}");
sb.append(contactViewHolder(map));
return sb.toString();
}
/**
* 連線字串:ViewHolder
*/
private static String contactViewHolder(HashMap<String, String> map) {
StringBuilder sb = new StringBuilder();
sb.append("class MyViewHolder extends RecyclerView.ViewHolder {\r\n");
map.forEach((id, view) -> {
if (view.contains("\n")) {
view = view.split("\n")[0];
}
sb.append("public ").append(view).append(" ")
.append(formatId2Field(id)).append(";").append("\r\n");
});
sb.append("public MyViewHolder(View itemView) {\n" +
"super(itemView);");
map.forEach((id, view) -> {
sb.append(formatId2Field(id))
.append("= itemView.findViewById(R.id.")
.append(id).append(");").append("\r\n");
});
sb.append("}\n" +
"}\n}");
return sb.toString();
}
private static String formatId2Field(String id) {
if (id.contains("_")) {
String[] partStrArray = id.split("_");
id = "";
for (String part : partStrArray) {
String partStr = upAChar(part);
id += partStr;
}
}
return "m" + id;
}
/**
* 將字串僅首字母大寫
*
* @param str 待處理字串
* @return 將字串僅首字母大寫
*/
public static String upAChar(String str) {
String a = str.substring(0, 1);
String tail = str.substring(1);
return a.toUpperCase() + tail;
}
private static HashMap<String, String> split(String res) {
String[] split = res.split("<");
HashMap<String, String> viewMap = new HashMap<>();
for (String s : split) {
if (s.contains("android:id=\"@+id") && !s.contains("Guideline")) {
String id = s.split("@")[1];
id = id.substring(id.indexOf("/") + 1, id.indexOf("\""));
String view = s.split("\r\n")[0];
String[] viewNameArr = view.split("\\.");
if (viewNameArr.length > 0) {
view = viewNameArr[viewNameArr.length - 1];
}
viewMap.put(id, view);
}
}
return viewMap;
}
}
複製程式碼
2.Attrs2View.java
/**
* 作者:張風捷特烈
* 時間:2018/10/31 0031:8:47
* 郵箱:1981462002@qq.com
* 說明:安卓自定義屬性,程式碼生成器
*/
public class Attrs2View {
@Test
public void main() {
//你的attr.xml所在路徑
File file = new File("I:\\Java\\Android\\Unit\\B\\test\\src\\main\\res\\values\\attrs.xml");
//你的Adapter的java類放在哪個包裡
File out = new File("I:\\Java\\Android\\Unit\\B\\asyn\\src\\main\\java\\com\\toly1994\\app");
String preFix = "z_";
//你的字首
initAttr(preFix, file, out);
}
public static void initAttr(String preFix, File file, File out) {
HashMap<String, String> format = format(preFix, file);
String className = format.get("className");
String result = format.get("result");
StringBuilder sb = initTop(out, className, result);
sb.append("TypedArray a = context.obtainStyledAttributes(attrs, R.styleable." + className + ");\r\n");
format.forEach((s, s2) -> {
String styleableName = className + "_" + preFix + s;
if (s.contains("_")) {
String[] partStrArray = s.split("_");
s = "";
for (String part : partStrArray) {
String partStr = upAChar(part);
s += partStr;
}
}
if (s2.equals("dimension")) {
// mPbBgHeight = (int) a.getDimension(R.styleable.TolyProgressBar_z_pb_bg_height, mPbBgHeight);
sb.append("m" + s + " = (int) a.getDimension(R.styleable." + styleableName + ", m" + s + ");\r\n");
}
if (s2.equals("color")) {
// mPbTxtColor = a.getColor(R.styleable.TolyProgressBar_z_pb_txt_color, mPbTxtColor);
sb.append("m" + s + " = a.getColor(R.styleable." + styleableName + ", m" + s + ");\r\n");
}
if (s2.equals("boolean")) {
// mPbTxtColor = a.getColor(R.styleable.TolyProgressBar_z_pb_txt_color, mPbTxtColor);
sb.append("m" + s + " = a.getBoolean(R.styleable." + styleableName + ", m" + s + ");\r\n");
}
if (s2.equals("string")) {
// mPbTxtColor = a.getColor(R.styleable.TolyProgressBar_z_pb_txt_color, mPbTxtColor);
sb.append("m" + s + " = a.getString(R.styleable." + styleableName + ");\r\n");
}
});
sb.append("a.recycle();\r\n");
sb.append("init();\n" +
" }");
sb.append("private void init() {\n" +
"\n" +
" }\n}");
System.out.println(sb.toString());
FileWriter fw = null;
try {
//寫出到磁碟
File outFile = new File(out, className + ".java");
fw = new FileWriter(outFile);
fw.write(sb.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
*
* @param out
* @param name
*/
private static StringBuilder initTop(File out, String name, String field) {
StringBuilder sb = new StringBuilder();
String path = out.getAbsolutePath();
path.split("java");
sb.append("package " + path.split("java\\\\")[1].replaceAll("\\\\", ".") + ";\n");
sb.append("public class " + name + " extends View {\n");
sb.append(field);
sb.append("public " + name + "(Context context) {\n" +
" this(context, null);\n" +
"}\n" +
"public " + name + "(Context context, AttributeSet attrs) {\n" +
" this(context, attrs, 0);\n" +
"}\n" +
"public " + name + "(Context context, AttributeSet attrs, int defStyleAttr) {\n" +
" super(context, attrs, defStyleAttr);\n");
return sb;
}
/**
* 讀取檔案+解析
*
* @param preFix 字首
* @param file 檔案路徑
*/
public static HashMap<String, String> format(String preFix, File file) {
HashMap<String, String> container = new HashMap<>();
if (!file.exists() && file.isDirectory()) {
return null;
}
FileReader fr = null;
try {
fr = new FileReader(file);
//字元陣列迴圈讀取
char[] buf = new char[1024];
int len = 0;
StringBuilder sb = new StringBuilder();
while ((len = fr.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
String className = sb.toString().split("<declare-styleable name=\"")[1];
className = className.substring(0, className.indexOf("\">"));
container.put("className", className);
String[] split = sb.toString().split("<");
String part1 = "private";
String type = "";//型別
String name = "";
String result = "";
String def = "";//預設值
StringBuilder sb2 = new StringBuilder();
for (String s : split) {
if (s.contains(preFix)) {
result = s.split(preFix)[1];
name = result.substring(0, result.indexOf("\""));
type = result.split("format=\"")[1];
type = type.substring(0, type.indexOf("\""));
container.put(name, type);
if (type.contains("color") || type.contains("dimension") || type.contains("integer")) {
type = "int";
def = "0";
}
if (result.contains("fraction")) {
type = "float";
def = "0.f";
}
if (result.contains("string")) {
type = "String";
def = "\"toly\"";
}
if (result.contains("boolean")) {
type = "boolean";
def = "false";
}
if (name.contains("_")) {
String[] partStrArray = name.split("_");
name = "";
for (String part : partStrArray) {
String partStr = upAChar(part);
name += partStr;
}
sb2.append(part1 + " " + type + " m" + name + "= " + def + ";\r\n");
}
container.put("result", sb2.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fr != null) {
fr.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return container;
}
/**
* 將字串僅首字母大寫
*
* @param str 待處理字串
* @return 將字串僅首字母大寫
*/
public static String upAChar(String str) {
String a = str.substring(0, 1);
String tail = str.substring(1);
return a.toUpperCase() + tail;
}
}
複製程式碼
3.Svg2Xml.java
/**
* 作者:張風捷特烈
* 時間:2018/10/31 0031:8:47
* 郵箱:1981462002@qq.com
* 說明:svg圖示轉換為Android可用xml生成器
*/
public class Svg2Xml {
@Test
public void svgDir() {
String dirPath = "E:\\Material\\MyUI\\#svg\\factory";
svg2xmlFromDir(dirPath);
}
@Test
public void singleSvg() {
File file = new File("C:\\Users\\Administrator\\Desktop\\dao.svg");
svg2xml(file);
}
/**
* 將一個資料夾裡的所有svg轉換為xml
*
* @param filePath
*/
public static void svg2xmlFromDir(String filePath) {
File file = new File(filePath);
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
if (f.getName().endsWith(".svg")) {
System.out.println(f);
svg2xml(f);
}
}
} else {
svg2xml(file);
}
}
/**
* 將.svg檔案轉換為安卓可用的.xml
*
* @param file 檔案路徑
*/
public static void svg2xml(File file) {
if (!file.exists() && file.isDirectory()) {
return;
}
FileWriter fw = null;
FileReader fr = null;
ArrayList<String> paths = new ArrayList<>();
try {
fr = new FileReader(file);
//字元陣列迴圈讀取
char[] buf = new char[1024];
int len = 0;
StringBuilder sb = new StringBuilder();
while ((len = fr.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
//收集所有path
collectPaths(sb.toString(), paths);
//拼接字串
StringBuilder outSb = contactStr(paths);
//寫出到磁碟
File outFile = new File(file.getParentFile(), file.getName().substring(0, file.getName().lastIndexOf(".")) + ".xml");
fw = new FileWriter(outFile);
fw.write(outSb.toString());
System.out.println("轉換成功:" + file.getName());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
if (fr != null) {
fr.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 拼接字串
*
* @param paths
* @return
*/
private static StringBuilder contactStr(ArrayList<String> paths) {
StringBuilder outSb = new StringBuilder();
outSb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
" android:width=\"48dp\"\n" +
" android:height=\"48dp\"\n" +
" android:viewportWidth=\"1024\"\n" +
" android:viewportHeight=\"1024\">\n");
for (String path : paths) {
outSb.append(" <path\n" +
" android:fillColor=\"#FF7F47\"\nandroid:pathData=\"");
outSb.append(path);
outSb.append("\"/>");
}
outSb.append("</vector>");
return outSb;
}
/**
* 收集所有path
*
* @param result
* @param paths
*/
private static void collectPaths(String result, ArrayList<String> paths) {
String regex = " d=\"(?<res>(.)*?)\"";
Matcher matcher = Pattern.compile(regex).matcher(result);
while (matcher.find()) {
String path = matcher.group("res");
paths.add(path);
}
}
}
複製程式碼
後記:捷文規範
1.本文成長記錄及勘誤表
專案原始碼 | 日期 | 備註 |
---|---|---|
V0.1-- | 2018-11-14 | 分享一下我的三個程式碼自動生成工具類--助你解放雙手 |
V0.2-- | 2018-12-7 | svg2Xml使用正則進行匹配 |
2.更多關於我
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
我的github | 我的簡書 | 我的掘金 | 個人網站 |
3.宣告
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大程式設計愛好者共同交流
3----個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4----看到這裡,我在此感謝你的喜歡與支援