Android Studio 生成 注入的插件

 Android Studio 生成 注入的插件

效果如图

本插件采用 IntelliJ IDEA 开发。插件主要代码如下。

本示例代码主要构成如下图,

其中,

plugin.xml                定义了一些插件的版本(<id></id>)、名称(<name></name>、描述(<description></description>、动作(<action></action> 等。

ButterKnifeIOC        动作的执行者类,里面写了些查找R.layout.xxxxx 布局的内容。并把查找的id等显示出来,即看到的gif的第一帧。

Element                  里面写了些,获取 R.id.xxxx ,变量名 的东西。其中

 // 命名1 aa_bb_cc; 2 aaBbCc 3 mAaBbCc
    private int fieldNameType = 1;

    /**
     * 获取id,R.id.id
     *
     * @return
     */
    public String getFullID() {
        StringBuilder fullID = new StringBuilder();
        String rPrefix = "R.id.";
        fullID.append(rPrefix);
        fullID.append(id);
        return fullID.toString();
    }

    /**
     * 获取变量名,变量名的生成方式在这里修改
     *
     * @return
     */
    public String getFieldName() {
        if (TextUtils.isEmpty(this.fieldName)) {
            String fieldName = id;
            String[] names = id.split("_");
            if (fieldNameType == 2) {
                // aaBbCc
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < names.length; i++) {
                    if (i == 0) {
                        sb.append(names[i]);
                    } else {
                        sb.append(Util.firstToUpperCase(names[i]));
                    }
                }
                fieldName = sb.toString();
            } else if (fieldNameType == 3) {
                // mAaBbCc
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < names.length; i++) {
                    if (i == 0) {
                        sb.append("m");
                    }
                    sb.append(Util.firstToUpperCase(names[i]));
                }
                fieldName = sb.toString();
            }
            this.fieldName = fieldName;
        }
        return this.fieldName;
    }
IdBean   定义gif 第一帧面板上的一些显示数据。其中
    /**
     * mFieldJTextField接口  ,布局id变量名在面板上修改的监听
     */
    public interface FieldFocusListener {
        void setFieldName(JTextField fieldJTextField);
    }

    /**
     * id注释接口 ,布局id变量名对应的注释在面板上修改的监听
     */
    public interface AnnotationForId {
        void setAnnotationForId(JTextField fieldJTextField);
    }
Util  定义的一些工具类,其中
  /**
     * 解析xml获取string的值
     *
     * @param psiFile
     * @param text
     * @return
     */
    public static String getTextFromStringsXml(PsiFile psiFile, String text) {
        psiFile.accept(new XmlRecursiveElementVisitor() {
            @Override
            public void visitElement(PsiElement element) {
                super.visitElement(element);
                if (element instanceof XmlTag) {
                    XmlTag tag = (XmlTag) element;
                    if (tag.getName().equals("string")
                            && tag.getAttributeValue("name").equals(text)) {
                        PsiElement[] children = tag.getChildren();
                        String value = "";
                        for (PsiElement child : children) {
                            value += child.getText();
                        }
                        // value = <string name="app_name">My Application</string>
                        // 用正则获取值
                        Pattern p = Pattern.compile("<string name="" + text + "">(.*)</string>");
                        Matcher m = p.matcher(value);
                        while (m.find()) {
                            StringValue = m.group(1);
                        }
                    }
                }
            }
        });
        return StringValue;
    }

    public static String getTextOrHintString(Element element, Project mProject) {
        // 设置变量名,获取text里面的内容
        String text = element.getXml().getAttributeValue("android:text");
        if (TextUtils.isEmpty(text)) {
            // 如果是text为空,则获取hint里面的内容
            text = element.getXml().getAttributeValue("android:hint");
        }
        // 如果是@string/app_name类似
        if (!TextUtils.isEmpty(text) && text.contains("@string/")) {
            text = text.replace("@string/", "");
            // 获取strings.xml
            PsiFile[] psiFiles = FilenameIndex.getFilesByName(mProject, "strings.xml", GlobalSearchScope.allScope(mProject));
            if (psiFiles.length > 0) {
                for (PsiFile psiFile : psiFiles) {
                    // 获取srcmain
esvalues下面的strings.xml文件
                    String dirName = psiFile.getParent().toString();
                    if (dirName.contains("src\main\res\values")) {
                        text = getTextFromStringsXml(psiFile, text);
                    }
                }
            }
        }
        return text;
    }
   /**
     * 获取所有id
     *
     * @param file
     * @param elements
     * @return
     */
    public static java.util.List<Element> getIDsFromLayout(final PsiFile file, final java.util.List<Element> elements) {
        // To iterate over the elements in a file
        // 遍历一个文件的所有元素
        file.accept(new XmlRecursiveElementVisitor() {
            @Override
            public void visitElement(PsiElement element) {
                super.visitElement(element);
                // 解析Xml标签
                if (element instanceof XmlTag) {
                    XmlTag tag = (XmlTag) element;
                    // 获取Tag的名字(TextView)或者自定义
                    String name = tag.getName();
                    // 如果有include
                    if (name.equalsIgnoreCase("include")) {
                        // 获取布局
                        XmlAttribute layout = tag.getAttribute("layout", null);
                        // 获取project
                        Project project = file.getProject();
                        // 布局文件
                        XmlFile include = null;
                        PsiFile[] psiFiles = FilenameIndex.getFilesByName(project, getLayoutName(layout.getValue()) + ".xml", GlobalSearchScope.allScope(project));
                        if (psiFiles.length > 0) {
                            include = (XmlFile) psiFiles[0];
                        }
                        if (include != null) {
                            // 递归
                            getIDsFromLayout(include, elements);
                            return;
                        }
                    }
                    // 获取id字段属性
                    XmlAttribute id = tag.getAttribute("android:id", null);
                    if (id == null) {
                        return;
                    }
                    // 获取id的值
                    String idValue = id.getValue();
                    if (idValue == null) {
                        return;
                    }
                    XmlAttribute aClass = tag.getAttribute("class", null);
                    if (aClass != null) {
                        name = aClass.getValue();
                    }
                    // 添加到list
                    try {
                        Element e = new Element(name, idValue,  tag);
                        elements.add(e);
                    } catch (IllegalArgumentException e) {

                    }
                }
            }
        });


        return elements;
    }
ViewFieldMethodCreator 创建代码插入Android studio 中的类里,其中 
   /**
     * 创建变量
     */
    private void generateFields() {
        for (Element element : mElements) {
            if (mClass.getText().contains("@BindView(" + element.getFullID() + ")")) {
                // 不创建新的变量
                continue;
            }
            StringBuilder fromText = new StringBuilder();
            String fieldJTextFieldLabel = element.getAnnotationForId();
            if (!TextUtils.isEmpty(fieldJTextFieldLabel)) {
                // 创建注释
                fromText.append("/*** ").append(fieldJTextFieldLabel).append(" **/
");
            }
            // 创建 注解和控件名称、变量 即 @BindView(R.id.xxx) View xxx
            fromText.append("@BindView(").append(element.getFullID()).append(")
");
            fromText.append(element.getName());
            fromText.append(" ");
            fromText.append(element.getFieldName());
            fromText.append(";");
            // 创建点击方法
            if (element.isCreateFiled()) {
                // 添加到class
                mClass.add(mFactory.createFieldFromText(fromText.toString(), mClass));
            }
        }
    }

FindViewByIdDialog 创建gif里的第一帧的图片上的数据,其中
定义了图片上头部和底部内容
  // 标签JPanel
    private JPanel mPanelTitle = new JPanel();
    private JLabel mTitleId = new JLabel("ViewId");
    private JLabel mTitleClick = new JLabel("OnClick");
    private JLabel mTitleField = new JLabel("ViewFiled");
    private JLabel mTitleLabel = new JLabel("ID注释");

 
    // 确定、取消JPanel
    private JPanel mPanelButtonRight = new JPanel();
    private JButton mButtonConfirm = new JButton("确定");
    private JButton mButtonCancel = new JButton("取消");

添加中间部分的内容

    /**
     * 解析mElements,并添加到JPanel
     */
    private void initContentPanel() {
        mContentJPanel.removeAll();
        // 设置内容
        for (int i = 0; i < mElements.size(); i++) {
            Element mElement = mElements.get(i);

            // 获取到id定义的文字并设置
            String textOrHintString = Util.getTextOrHintString(mElement, mProject);
            mElement.setAnnotationForId(textOrHintString);

            IdBean itemJPanel = new IdBean(new GridLayout(1, 5, 10, 10),
                    JBUI.Borders.empty(5, 10),
                    new JCheckBox(mElement.getName()),
                    new JLabel(mElement.getId()),
                    new JCheckBox(),
                    new JTextField(mElement.getFieldName()),
                    new JTextField(mElement.getAnnotationForId()),
                    mElement);
            // 监听
            itemJPanel.setEnableActionListener(this);
            itemJPanel.setClickActionListener(clickCheckBox -> mElement.setIsCreateClickMethod(clickCheckBox.isSelected()));
            itemJPanel.setFieldFocusListener((fieldJTextField) -> {
                mElement.setFieldName(fieldJTextField.getText()); // 从输入框获取id变量数据
            });

            // id注释接口,获取写入的id注释文字
            itemJPanel.setAnnotationForIdFocusListener(fieldJTextField -> mElement.setAnnotationForId(fieldJTextField.getText()));

            mContentJPanel.add(itemJPanel);
            mContentConstraints.fill = GridBagConstraints.HORIZONTAL;
            mContentConstraints.gridwidth = 0;
            mContentConstraints.gridx = 0;
            mContentConstraints.gridy = i;
            mContentConstraints.weightx = 1;
            mContentLayout.setConstraints(itemJPanel, mContentConstraints);
        }
        mContentJPanel.setLayout(mContentLayout);
        jScrollPane = new JBScrollPane(mContentJPanel);
        jScrollPane.revalidate();
        // 添加到JFrame
        getContentPane().add(jScrollPane, 1);
    }
提示,
1、若要改变命名规则,请到 “Element” 中修改
2、若要改变生成的代码(即 @BindView(R.id.xxx) View xxx) 请到 “ViewFieldMethodCreator”中修改

代码下载地址:https://github.com/suiyuanyimeng/butterknifeioc.git

原文地址:https://www.cnblogs.com/springl/p/9617199.html