动态换肤之从SD卡中的xml中获取ColorStateList

ColorStateList value = new ColorStateList(states, colors);

看到ColorStateList的构造方法,我们知道要想获得一个ColorStateList,需要有一个

int[][]

和一个存放ColorRes的

int[]

先看看一个很常用selector结构的color.xml

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#ffffff" android:state_enabled="true" android:state_pressed="true"/>
    <item android:color="#000000"/>
</selector>

要想解析这么一个xml文档,要用到xml解析库,我用的是jsoup,在AndroidStudio中的gradle添加

compile 'org.jsoup:jsoup:1.8.2'

就可以使用这个库了。

final File colorDir = new File(skinDirectory, "color");//指定SD卡目录下的color文件夹,这个目录由外部传入
                if (colorDir.exists()) {
                    final File[] files = colorDir.listFiles(mXmlFilter);
                    for (File file : files) {
                        final Document parse = Jsoup.parse(file, "UTF-8");//将xml文件解析成Document对象
                        final Elements selectors = parse.getElementsByTag("selector");//拿到selector节点列表,实际上列表中只有一个selector
                        if (selectors.isEmpty()) {
                            continue;
                        }
                        final Element selector = selectors.get(0);
                        final Elements children = selector.children();
                        int[][] states = new int[children.size()][];
                        int[] colors = new int[children.size()];
                        for (int i = 0; i < children.size(); i++) {
                            Element child = children.get(i);
                            if ("item".equals(child.tagName())) {//拿到item节点
                                final Attributes attributes = child.attributes();//item节点的属性集
                                String value = attributes.get("android:color");
                                final int parseColor = Color.parseColor(value);
                                states[i] = getStatesArr(attributes);
                                colors[i] = parseColor;
                            }
                        }
                        ColorStateList value = new ColorStateList(states, colors);

这段代码里主要是将每个item的属性取出来,比如android:color 就是item的一个属性,取到color的值,通过Color.parseColor转换成ColorInt。

private int[] getStatesArr(Attributes attributes) {
        List<Integer> stateList = new ArrayList<>();
        String attributePress = attributes.get("android:state_pressed");
        if (!TextUtils.isEmpty(attributePress)) {
            boolean isPressed = Boolean.parseBoolean(attributePress);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_pressed);
        }
        String attributeFocus = attributes.get("android:state_focused");
        if (!TextUtils.isEmpty(attributeFocus)) {
            boolean isPressed = Boolean.parseBoolean(attributeFocus);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_focused);
        }
        String attributeSelect = attributes.get("android:state_selected");
        if (!TextUtils.isEmpty(attributeSelect)) {
            boolean isPressed = Boolean.parseBoolean(attributeSelect);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_selected);
        }
        String attributeActive = attributes.get("android:state_active");
        if (!TextUtils.isEmpty(attributeActive)) {
            boolean isPressed = Boolean.parseBoolean(attributeActive);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_active);
        }
        String attributeCheckable = attributes.get("android:state_checkable");
        if (!TextUtils.isEmpty(attributeCheckable)) {
            boolean isPressed = Boolean.parseBoolean(attributeCheckable);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_checkable);
        }
        String attributeChecked = attributes.get("android:state_checked");
        if (!TextUtils.isEmpty(attributeChecked)) {
            boolean isPressed = Boolean.parseBoolean(attributeChecked);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_checked);
        }
        String attributeEnable = attributes.get("android:state_enabled");
        if (!TextUtils.isEmpty(attributeEnable)) {
            boolean isPressed = Boolean.parseBoolean(attributeEnable);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_enabled);
        }
        String attributeWindowFocus = attributes.get("android:state_window_focused");
        if (!TextUtils.isEmpty(attributeWindowFocus)) {
            boolean isPressed = Boolean.parseBoolean(attributeWindowFocus);
            stateList.add((isPressed ? 1 : -1) * android.R.attr.state_window_focused);
        }
        if(stateList.isEmpty()){
            return new int[]{};
        }else{
            int[] stateArr =new int[stateList.size()];
            for (int i=0;i<stateList.size();i++){
                stateArr[i] =stateList.get(i);
            }
            return stateArr;
        }
    }

这是取每个状态对应的int值,比如android:state_pressed为true,添加android.R.attr.state_pressed到数组中,如果为false添加 -android.R.attr.state_pressed,负的。

时间: 2024-11-07 09:59:30

动态换肤之从SD卡中的xml中获取ColorStateList的相关文章

Android动态换肤开源库Colorful发布

最近本人需要用到夜间模式,但是经过一番搜索似乎并没有看到好的开源实现,看到有一个类似的库MultipleTheme,但是需要自定义所有要实现换肤功能的View,感觉比较麻烦.当发现现有的解决方案不能很好的解决问题时,往往只能自己实现,因此本人花了点时间简单弄了一个实现该功能的开源库,命名为Colorful. Colorful是基于Theme,无需重启Activity.无需自定义View,方便的实现日间.夜间模式,github地址为 https://github.com/bboyfeiyu/Col

DevExpress 动态换肤

我们都知道Devexpress内置了很多themes,那要怎么在使用时动态更改呢. 下面是方法以: 1.如果你们已经有主题了,那就在XAML中删除类似下下面的语句. dx:ThemeManager.ThemeName="LightGray" 2.确保你的XAML中Window是引用下面的 <dx:DXWindow 后台也一样: MainWindow : DXWindow 3.下面就可以读取DevExpress中所有的主题: comboBoxEdit1.ItemsSource =

Android动态换肤(一、应用内置多套皮肤)

动态换肤在很多android应用中都有使用,用户根据自己的喜好设置皮肤主题,可以增强用户使用应用的舒适度. Android换肤可以分为很多种,它们从使用方式,用户体验以及项目框架设计上体现了明显的差异. 接下来几篇文章分别讲解其中比较主流的换肤方式. 应用内置皮肤实现动态切换在技术上是最容易实现的,但有很多局限性,比如不能在使用过程中增减皮肤,除非升级应用,扩展性很弱:如果需要设置皮肤的位置很多,编码起来比较麻烦.主要是使用 SharedPreferences记录当前设置的皮肤序号,然后加载这套

Cocos2d-x 3.0 cocostudio骨骼动画的动态换肤

概述 游戏中人物的状态会发生改变,而这种改变通常要通过局部的变化来表现出来.比如获得一件装备后人物形象的改变,或者战斗中武器.防具的损坏等.这些变化的实现就要通过动态换肤来实现.在接下来的这个Demo中,点击屏幕会动态更换小人手中的武器.先上图: 制作动画 我这里使用cocostudio自带的动画工程,HeroAnimation,打开. 添加我们的资源 插入渲染资源 更多内容还请移步 http://www.sollyu.com/562/ Cocos2d-x 3.0 cocostudio骨骼动画的

hybird之web动态换肤实现

前言 最近在重构个hybird(原生的壳包着Web页面)的UI框架,进行到了做换肤功能的阶段,所以这里是我思考的解决的方法. 预想 目前实现换肤的功能无非就两种做法. 1.写几个皮肤文件,然后切换使用这几个文件达到换肤的目的. 不得不说这是最常见的方式,效果也比较明显,但是它有几个缺点. 缺点: 1.如果更改一个皮肤的内容,那其他的皮肤文件也要做相应修改(这挺麻烦,不过可以用less管理css解决,所以也不是什么大问题). 2.它是固定的,在使用的时候皮肤文件已经是写好的了,而当我需要动态设置一

SD卡路径问题以及如何获取SDCard 内存

昨天在研究拍照后突破的存储路径的问题,开始存储路径写死为:    private String folder = "/sdcard/DCIM/Camera/"(SD卡上拍照程序的图片存储路径); 后来发现这样写虽然一般不会出错,但不是很好,因为不同相机,可能路径会出问题.较好的方法是通过Environment 来获取路径,最后给出一个例子,教你怎样获取SDCard 的内存,显示出来告诉用户.讲述的内容如下:     0.获取sd卡路径.      1.讲述 Environment 类.

SpringMVC项目中web.xml中的节点加载顺序问题

SpringMVC项目中web.xml中的节点加载顺序问题,之前以为web.xml中就是一些配置信息,和节点的顺序没有关系,后来才发现初始化时的加载顺序是和节点的顺序相关的. 完整的web.xml文件内容: <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns=&quo

Mybatis中mapper.xml中的模糊查询

Mybatis中mapper.xml中的模糊查询 <!-- 方法一: 直接使用 % 拼接字符串 注意:此处不能写成 "%#{name}%" ,#{name}就成了字符串的一部分, 会发生这样一个异常: The error occurred while setting parameters, 应该写成: "%"#{name}"%",即#{name}是一个整体,前后加上% --> <if test="name != nul

Genymotion中SD卡目录在Eclipse中查看,以及创建SDCard

今天写的Android程序在用Google自带的AVD4.4版本运行的,其中sd卡目录在/storage/sdcard/中,但是呀,自己的机器不给力启动一下5分多,程序员的时间是宝贵的,5分多可以敲好几十行代码了,所以就切回Eclipse边写代码边等它启动起来,但是有个东西在后面挂着,这敲着代码老是惦记着它启动了没有,后来忍受不了了,这就开始使用Genymotion这个模拟器了. 接下来就是找到Android Genymotion 模拟器的SD卡的目录. 这模拟器说真的就是启动快,和真机没啥太大