您好,欢迎访问代理记账网站
移动应用 微信公众号 联系我们

咨询热线 -

电话 15988168888

联系客服
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

Android自动生成Shape资源文件(下)

 系列文章目录

第一章:Android自动生成代码,可视化脚手架,将大大提高开发效率
第二章:Android自动生成代码,可视化脚手架之环境搭建
第三章:Android自动生成代码,可视化脚手架之基础信息配置
第四章:Android自动生成Shape资源文件,迈出可视化脚手架第一步(上)


系列文章Github开源地址(源码及各项资料不间断进行更新):

https://github.com/AbnerMing888/AndroidShortcutTools

上半部分,我们已经实现了可视化的基本信息配置,也就是可视化的第一个页面,这仅仅是一个前奏,在第一章里,我已经罗列了很多的功能,所以啊老铁们,抽个时间一定要去前边看一看,因为很多人的问题,我基本上前边都已经给出了解答,比如为什么不采用Android studio里的插件实现,工具在哪下载等等,都诉说的很清楚,这里就不一一赘述了,我们继续上半部分陈述。

针对Shape的实现,是可视化脚手架里最简单的,因为没有什么逻辑可言,都是现成的模板,无非就是改里面的属性而已,老铁们,记住啊,可视化说到底,确实没有什么技术含量,大多都是动态的更改,比如这个Shape,在正常的开发中,无非就是,实心的,空心的,渐变的,左上右下带角度的,那么针对常见的几种方式,我们做好模板,然后根据你在可视化工具的选择,动态的进行改变即可。

细节的源码,大家可以直接去GitHub上下载浏览,文章里就不过多的赘述,我们主要说下具体的实现方式。

 一、页面绘制及保存到drawable文件夹下。

可视化的工具,之前说过,采用的是Web开发,相对于Android而言,还是比较简单的,无非就是各个标签的罗列,针对这个最终效果,毕竟我也不是搞Web开发的,也没有一个UI设计,所有的效果都是自己根据实际业务而来的,丑是丑了点,大家可以将就着看哈。

具体的页面,大家可以看源码中的shape.html这个文件,都是div标签,就不贴了,没啥好说的。4

选择对应生成文件夹,这个功能是在你选择项目或者一个文件夹的时候,下面有很多的子目录,或者说直接是Module,这种情况下,你就可以进行选择生成到哪个Module下,这个选择是根据基础配置里的选择路径而来的,所以啊,基础配置选择项目生成路径,大家尽量选择一个Android项目。选择生成到哪个Module下之后,就会自动在保存在对应的res下的drawable文件夹下。

如何根据选择的Android项目,保存到对应的drawable下呢?这个就很简单了,项目路径(基础配置页面选择的路径)加上当前页面选择的生成文件夹路径,就可以很好的知道对应的drawable路径了。

每个module下的drawable是固定的,无非在上边的两个路径下,拼接后边的drawable路径即可。

如下图代码,selectPath是基础配置页面里选择的项目路径,selectFile是你选择的路径,后边拼接固定的 /src/main/res即可,再后面就是shape文件资源的名字了。

有一个需要注意的点是,drawable文件夹可能不在,那么你就要判断drawable是否存在了,存在就执行写入,不存在,就先创建drawable文件夹,然后在执行写入,这个写入就是,写入生成shape的代码,后面会说到。

//先判断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项目。

//检测选择的是否是一个Android项目,通过是否包含app,gradle,settings.gradle,当然也可以判断其他
if (item === "app" || item === "gradle" || item === "settings.gradle") {
    numAndroid++;
}

是Android项目就可以生成到对应的drawable下,否则就普通文件夹下,具体可以看源码示例。

 二、根据对应模板代码和UI视图选择,生成对应的资源

模板是固定的,唯一改变的就是里面的属性,比如下图,无非就是radius和color里属性需要改,其他的都是固定的,需要改的就要绘制相关的UI视图了。

目前的UI视图,很简单,无非就是三个功能,实心,空心,和渐变,当然了,这是我定义的,如果你还有拓展的功能,可以自己在源码中自己拓展。

   

根据这三个功能,我们定义好固定的三个模板,根据视图中相关选择,动态改变即可。

实心模板,注意看相关注释。 

实现代码,需要注意,这里我在视图中,定义了左上,右上,左下,右下,四个选择框,就是对应代码里左上右下相关的角度,依次对应的点击记录为,0,1,2,3。

//获取实心的代码
function getSolidText(radius, color, checkText) {
    var content = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
        "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\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 + "    <corners android:radius=\"" + radius + "\"></corners>\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 + "    <solid android:color=\"" + color + "\" />\n";
    content = content + "</shape>";
    return content;
}

空心(带有边框的shape)模板

和实心的区别就是,加了一个边框,其他的都没怎么变。

代码实现:

//获取空心也就是带有边框的代码
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 + "    <corners android:radius=\"" + radius + "\" />\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 + " <solid android:color=\"" + solid + "\"/>\n";
    content = content + "</shape>"
    return content;
}

渐变模板:

   代码实现:

//获取渐变
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" +
        "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\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 + "    <corners android:radius=\"" + radius + "\"></corners>\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 + "</shape>";
    return gradient;
}

当然了具体逻辑相关的,大家可以查看源码,有任何问题,也可以留言咨询。

选择颜色这块用到了一个三方,也放到源码里面了,方便大家进行取色,UI图里特意设置了一个名字,因为shape资源生成有一定的规范用名,特别是在组件化开发的项目,所以简单的设置了一下规范用名,可以一键获取,根据你设置的颜色,角度来进行填充。

Shape的可视化生成就是如此的简单,好了各位老铁,下一篇,我们搞一个可视化的多渠道打包,一秒可生成N个渠道包,敬请期待!


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进