Android中动态的更改selector中某张图片的属性
2015-09-08 15:16
645 查看
在我们平常开发的时候会有许多状态按钮,比如state_pressed,android:state_checked,或者就正常状态等等,我们做这样的效果通常需要三个文件,一张是按下的图片,一张是正常状态的图片,一张是管理它们的selector文件,如果在不断更新迭代的过程中出现了很多这样的按钮,而且它们的颜色什么的都不一样,那我们的res/drawable文件夹下就会出现很多个这样的组合文件,导致我们的程序越来越大、越来越大,这肯定不是我们想看到的。
那么,我现在要拿出什么来解决这个问题呢?就是动态的更改它们的属性,把所有的工作都放在代码里面,减少selector.xml文件的产生:
我们在写属性的时候尽量要使用这样的方式(如果美工给了图的话,尽量让提供颜色值就可以了,不要做那么多图):
布局文件:
这个xml文件的正常显示效果是:
效果还是挺不错的,接下来我们要动态改变它的效果,怎么做呢:
怎么样,效果实现了我们需要的。
最后,贴上一个抽取出来的工具类:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
public class SelectorUtils {
/**
* 动态修改selector中图片的背景颜色
*
* @param drawable
* selectorDrawable
* @param rgbColors
* 默认以及按下状态的颜色值
*/
public static void changeViewColor(StateListDrawable drawable, int[] rgbColors) {
ConstantState cs = drawable.getConstantState();
if (rgbColors.length < 2) {
return;
}
try {
Method method = cs.getClass().getMethod("getChildren", null);// 通过反射调用getChildren方法获取xml文件中写的drawable数组
method.setAccessible(true);
Object obj = method.invoke(cs, null);
Drawable[] drawables = (Drawable[]) obj;
for (int i = 0; i < drawables.length; i++) {
// 接下来我们要通过遍历的方式对每个drawable对象进行修改颜色值
GradientDrawable gd = (GradientDrawable) drawables[i];
if (gd == null) {
break;
}
if (i == 0) {
// 我们对按下的状态做浅色处理
gd.setColor(rgbColors[0]);
} else {
// 对默认状态做深色处理
gd.setColor(rgbColors[1]);
}
}
// 最后总结一下,为了实现这个效果,刚开始并没有看到setColor的方法,而是通过反射获取GradientDrawable对象的属性GradientState,
// 再通过反射调用GradientState对象的setSolidColor方法去实现,效果不太理想。
// 最后在仔仔细细一一看GradientDrawable对象的属性,发现属性Paint
// mFillPaint,从名字就可以看出这个对象是用来绘制drawable的背景的,
// 于是顺着往下找,发现setColor方法,于是bingo,这个过程也是挺曲折的。
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
有疑问欢迎留言。
那么,我现在要拿出什么来解决这个问题呢?就是动态的更改它们的属性,把所有的工作都放在代码里面,减少selector.xml文件的产生:
我们在写属性的时候尽量要使用这样的方式(如果美工给了图的话,尽量让提供颜色值就可以了,不要做那么多图):
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"><shape> <corners android:radius="5dp" /> <solid android:color="#78909c" /> </shape></item> <item><shape> <corners android:radius="5dp" /> <solid android:color="#607d8b" /> </shape></item> </selector></span>
布局文件:
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="Hello" android:textColor="#fff" /> </FrameLayout></span>
这个xml文件的正常显示效果是:
效果还是挺不错的,接下来我们要动态改变它的效果,怎么做呢:
<span style="font-size:12px;">package com.sahadev.activitythemetest; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import android.app.Activity; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable.ConstantState; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.StateListDrawable; import android.os.Bundle; import android.widget.Button; public class MainActivity2 extends Activity { // Hold a reference to the current @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_zoom); Button button = (Button) findViewById(R.id.button); Drawable backgroundDrawable = getResources().getDrawable(R.drawable.xml_background); button.setBackground(backgroundDrawable); StateListDrawable sld = (StateListDrawable) backgroundDrawable;// 通过向下转型,转回原型,selector对应的Java类为:StateListDrawable ConstantState cs = sld.getConstantState(); try { Method method = cs.getClass().getMethod("getChildren", null);// 通过反射调用getChildren方法获取xml文件中写的drawable数组 method.setAccessible(true); Object obj = method.invoke(cs, null); Drawable[] drawables = (Drawable[]) obj; for (int i = 0; i < drawables.length; i++) { // 接下来我们要通过遍历的方式对每个drawable对象进行修改颜色值 GradientDrawable gd = (GradientDrawable) drawables[i]; if (gd == null) { break; } if (i == 0) { // 我们对按下的状态做浅色处理 gd.setColor(Color.rgb(155, 155, 155)); } else { // 对默认状态做深色处理 gd.setColor(Color.rgb(75, 75, 75)); } } // 最后总结一下,为了实现这个效果,刚开始并没有看到setColor的方法,而是通过反射获取GradientDrawable对象的属性GradientState, // 再通过反射调用GradientState对象的setSolidColor方法去实现,效果不太理想。 // 最后在仔仔细细一一看GradientDrawable对象的属性,发现属性Paint // mFillPaint,从名字就可以看出这个对象是用来绘制drawable的背景的, // 于是顺着往下找,发现setColor方法,于是bingo,这个过程也是挺曲折的。 } catch (NoSuchMethodException e1) { e1.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } </span>方法就是这样,我们再来看看最后的实现效果:
怎么样,效果实现了我们需要的。
最后,贴上一个抽取出来的工具类:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
public class SelectorUtils {
/**
* 动态修改selector中图片的背景颜色
*
* @param drawable
* selectorDrawable
* @param rgbColors
* 默认以及按下状态的颜色值
*/
public static void changeViewColor(StateListDrawable drawable, int[] rgbColors) {
ConstantState cs = drawable.getConstantState();
if (rgbColors.length < 2) {
return;
}
try {
Method method = cs.getClass().getMethod("getChildren", null);// 通过反射调用getChildren方法获取xml文件中写的drawable数组
method.setAccessible(true);
Object obj = method.invoke(cs, null);
Drawable[] drawables = (Drawable[]) obj;
for (int i = 0; i < drawables.length; i++) {
// 接下来我们要通过遍历的方式对每个drawable对象进行修改颜色值
GradientDrawable gd = (GradientDrawable) drawables[i];
if (gd == null) {
break;
}
if (i == 0) {
// 我们对按下的状态做浅色处理
gd.setColor(rgbColors[0]);
} else {
// 对默认状态做深色处理
gd.setColor(rgbColors[1]);
}
}
// 最后总结一下,为了实现这个效果,刚开始并没有看到setColor的方法,而是通过反射获取GradientDrawable对象的属性GradientState,
// 再通过反射调用GradientState对象的setSolidColor方法去实现,效果不太理想。
// 最后在仔仔细细一一看GradientDrawable对象的属性,发现属性Paint
// mFillPaint,从名字就可以看出这个对象是用来绘制drawable的背景的,
// 于是顺着往下找,发现setColor方法,于是bingo,这个过程也是挺曲折的。
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
有疑问欢迎留言。
相关文章推荐
- android 组件设置屏幕大小
- android下升级软件介绍
- View的Touch事件分发流程
- Android ListView嵌套ListView的实现方式
- android悬浮窗口的实现
- Android开发学习笔记:数据存取之SQLite浅析
- Android中的Service详解
- Android drawable resource error:No resource found that matches the……
- Android --MainActivity模板
- android openfire 表中各状态之间数值标记
- android 多渠道打包的概念及方法
- Android textColor、按钮按下抬起颜色变换
- NineOldAndroids 使用
- Android向通知栏发送通知并且不让被清理掉,一直占领通知栏
- Android GestureDetector手势识别与多点触控探究
- Android触控屏幕Gesture(GestureDetector和SimpleOnGestureListener的使用教程)
- Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android Input输入子系统分析
- 【Android笔记】各个屏幕的logo尺寸要求