• 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

  • 相关阅读:
    LeetCode【125. 验证回文串】
    LeetCode【122. 买卖股票的最佳时机 II】
    LeetCode【121. 买卖股票的最佳时机】
    LeetCode【119. 杨辉三角 II】
    LeetCode【118. 杨辉三角】
    LeetCode【112. 路径总和】
    PAT1024
    PAT1020
    PAT1018
    PAT1017
  • 原文地址:https://www.cnblogs.com/springl/p/9617199.html
Copyright © 2020-2023  润新知