Zero, Preface:

1.RecyclerView Adapter automatic generator (including ViewHolder)

2. Custom View code generator for custom attributes (including initialization of custom attributes) 3. Convert SVG ICONS into XML generators available for Android

I like cutting strings recently. These three classes are my recent works. I feel very good to use them

All three tools are posted at the end of this article, the end of this article, and the end of this article


RecyclerView Adapter automatic generator (including ViewHolder)

Recently, I wrote several RecyclerView adapters, and many ViewHolder controls feel quite uncomfortable to write

It’s just a few ids in the layout file that are different from the View type, so let’s write a tool to read the XML and generate the View automatically. Since the ViewHolder generates the View automatically, let’s also generate the Adapter

To demonstrate:

1. Copy the utility classes to the Test package

2. Write the path to your XML and the generated.java package. 3. Please point out any questions you have


Xml code
<? The 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>Copy the code
Automatically generated Adapter

Click on it, it will generate so much, one by one it will take five minutes, this boring work, or leave it to the computer.

Then, depending on your business needs, make small fixes.


Bonus: findViewById is automatically generated, in the console, ready to copy

Although I like to use butterknife, I feel that it is troublesome to add a dependency every time. Even if I want to find an ID, there is no need to introduce a library. After all, it takes up space.


2. Custom View code generator for custom attributes (including initialization of custom attributes)

This can be described as my proud work, I prefer to custom control, but custom zodiac to write up a lot of effort, there is no content

Basically, there are only a few properties that are changing, so let’s write a tool class, and then we have the following:

Demonstrate the use of:

1. Copy the utility classes to the Test package

2. Write the path to your XML and the generated.java package, with your own prefix 3. Click Run and you can generate it. If you have any problems, please note that custom attributes must have their own special prefix (any character is ok, but uniform).


Attrs. XML file:
<? The 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>Copy the code


3. Convert SVG ICONS into XML generators available for Android

As above, put all SVG in one folder and batch it


The appendix

1: Xml2Adapter. Java
/**
 * 作者:张风捷特烈
 * 时间:2018/10/31 0031:8:47
 * 邮箱:[email protected]
 * 说明:初始化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;
    }
}
Copy the code

2.Attrs2View.java
/**
 * 作者:张风捷特烈
 * 时间:2018/10/31 0031:8:47
 * 邮箱:[email protected]
 * 说明:安卓自定义属性,代码生成器
 */
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;
    }
}

Copy the code

3.Svg2Xml.java
/** * Author: Zhang Fengjieteilie * Time: 2018/10/31 0031:8:47 * Email: [email protected] * Description: 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); } 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); @param file path */ 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)); } // Collect all 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(" convert successfully: "+ file.getName()); } catch (Exception e) { e.printStackTrace(); } finally { try { if (fw ! = null) { fw.close(); } if (fr ! = null) { fr.close(); } } catch (Exception e) { e.printStackTrace(); Private static StringBuilder contactStr(ArrayList<String> Paths) {private static StringBuilder contactStr(ArrayList<String> Paths) { StringBuilder outSb = new StringBuilder(); outSb.append("<? The 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; } /** * Private static void collectPaths(String result paths) 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); }}}Copy the code

Postscript: Jiwen specification

1. Growth records and errata of this paper
Program source code The date of note
V0.1– 2018-11-14 Share three of my code generation tools to help you get your hands free
V0.2– The 2018-12-7 Svg2Xml uses re for matching
2. More about me
Pen name QQ WeChat hobby
Zhang Fengjie special lie 1981462002 zdl1994328 language
My lot My Jane books I’m the nuggets Personal website
3. The statement

1—- This article was originally written by Zhang Fengjie, please note when reprinted

4—- see here, I thank you for your love and support