使用装饰器模式动态设置Drawable的ColorFilter
来源:互联网 发布:vba 网页数据抓取 编辑:程序博客网 时间:2024/06/08 03:15
使用装饰器模式动态设置Drawable的ColorFilter
欢迎各位关注我的新浪微博:微博
转载请标明出处(kifile的博客)
很多时候我们都希望Android控件点击的时候,有按下效果,选中时有选中效果。通常我们都是通过使用selector来生成一个StateListDrawable来实现。
可是这样我们会面临一个问题,如果使用selector的xml文件生成,那么对于不同的状态,我们就会需要不同的图片,才能够实现drawable的动态改变。
可是有时候,我们的按下状态同普通状态之间唯一的区别只是颜色的差异。那么这个时候,我们真的有必要在resources中放入多个颜色不同的图片吗?
或许很多人不会太在意几张图片的空间消耗,但是有时候,放着放着,包体就变大了。为了减小包体,我们真的有必要只放置一张图片,然后设置他在不同状态下的色值。
首先附上我写的一个Drawable装饰器:
package com.kifile.android.drawable;import android.graphics.Canvas;import android.graphics.ColorFilter;import android.graphics.PorterDuff;import android.graphics.PorterDuffColorFilter;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.util.StateSet;/** * 根据当前状态选择色值过滤器的Drawable. * <p/> * 使用{@link #addState(int[], int)} 添加色值. * * @author kifile */public class ColorFilterStateListDrawable extends Drawable implements Drawable.Callback { private Drawable mDrawable; private StateListState mStateSets; private int[] mCurrentState; public ColorFilterStateListDrawable(Drawable drawable) { if (drawable == null) { throw new IllegalArgumentException("drawable cannot be null."); } mStateSets = new StateListState(); mDrawable = drawable; mDrawable.setCallback(this); } public void addState(int[] stateSet, int color) { mStateSets.addStateSet(stateSet, color); } @Override public void draw(Canvas canvas) { ColorFilter filter = selectColorFilter(); if (filter != null) { mDrawable.setColorFilter(filter); } mDrawable.draw(canvas); } private ColorFilter selectColorFilter() { if (mCurrentState == null) { return null; } int index = mStateSets.indexOfStateSet(mCurrentState); int color = mStateSets.getColor(index); return new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP); } @Override public boolean getPadding(Rect padding) { return mDrawable.getPadding(padding); } @Override public int getIntrinsicHeight() { return mDrawable.getIntrinsicHeight(); } @Override public int getIntrinsicWidth() { return mDrawable.getIntrinsicWidth(); } @Override public int getMinimumHeight() { return mDrawable.getMinimumHeight(); } @Override public int getMinimumWidth() { return mDrawable.getMinimumWidth(); } @Override public int getChangingConfigurations() { return mDrawable.getChangingConfigurations(); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); mDrawable.setBounds(bounds); } @Override public void setAlpha(int alpha) { mDrawable.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { mDrawable.setColorFilter(cf); } @Override public int getOpacity() { return mDrawable.getOpacity(); } @Override protected boolean onStateChange(int[] state) { mCurrentState = state; return mDrawable.setState(state); } @Override public boolean isStateful() { return true; } @Override public void invalidateDrawable(Drawable who) { if (who == mDrawable && getCallback() != null) { getCallback().invalidateDrawable(this); } } @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { if (who == mDrawable && getCallback() != null) { getCallback().scheduleDrawable(this, what, when); } } @Override public void unscheduleDrawable(Drawable who, Runnable what) { if (who == mDrawable && getCallback() != null) { getCallback().unscheduleDrawable(this, what); } } private static class StateListState { private static final int INITIAL_SIZE = 5; int mNumChildren; int[][] mStateSets; int[] mColors; StateListState() { mStateSets = new int[INITIAL_SIZE][]; mColors = new int[INITIAL_SIZE]; } int addStateSet(int[] stateSet, int color) { final int pos = addChild(color); mStateSets[pos] = stateSet; return pos; } public final int addChild(int color) { final int pos = mNumChildren; if (pos >= mColors.length) { growArray(pos, pos + 10); } mColors[pos] = color; mNumChildren++; return pos; } private void growArray(int oldSize, int newSize) { int[] newColors = new int[newSize]; System.arraycopy(mColors, 0, newColors, 0, oldSize); mColors = newColors; final int[][] newStateSets = new int[newSize][]; System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize); mStateSets = newStateSets; } int indexOfStateSet(int[] stateSet) { final int[][] stateSets = mStateSets; final int N = getChildCount(); for (int i = 0; i < N; i++) { if (StateSet.stateSetMatches(stateSets[i], stateSet)) { return i; } } return -1; } public final int getChildCount() { return mNumChildren; } public int getColor(int index) { if (index >= 0 && index < mColors.length) { return mColors[index]; } return 0; } }}
简单介绍一下写这个装饰器的基本思路吧
这个类其实也挺简单的,就是使用装饰器模式包装了一个Drawable对象,然后将涉及到会引起界面变化的类都分发到所包装的drawable里。
核心代码其实在于,初始化drawable的时候,通过addState加入一个状态和该状态指定的Color色值,然后在draw()的时候,通过当前的状态去匹配当前应该显示的色值,然后通过setColorFilter设置应该显示的色值,从而令drawable显示的色值发生变化。
另外匹配当前状态的代码参考自StateListDrawable。
1 0
- 使用装饰器模式动态设置Drawable的ColorFilter
- ColorFilter的使用
- 使用ColorFilter
- 使用反射增加装饰模式的普适性,动态代理实现装饰模式
- Android中ColorFilter滤色器的使用
- 动态设置TextView的drawable属性
- 使用装饰器模式
- 动态设置 drawable-left...
- 【ThinkingInJava】43、与动态代理混合的装饰器模式
- 给ImageButton 设置ColorFilter
- Android --- ColorFilter使用
- 27 API-反射(类的加载器,反射的使用,动态代理)&设计模式(装饰设计模式,模版设计模式)&JDK新特性(JDK5,JDK6,JDK7,DK8)
- 设计模式:装饰器模式(为对象动态的添加功能)
- 使用装饰器模式做类的增强
- ColorFilter
- ColorFilter
- ColorFilter
- 装饰者设置模式和代理模式的区别
- c++11 移动语意 gcc 实测
- Linux系统编程——进程的控制:结束进程、等待进程结束
- iOS多线程编程工具
- OpenCV人脸识别facerec源码分析2――LBPH概述
- 1.结构体
- 使用装饰器模式动态设置Drawable的ColorFilter
- Android application 的使用
- cmake使用示例与整理总结
- iOS网络篇---使用NSSession 实现获取XML
- [LeetCode] Jump Game II
- A Magic Lamp(RMQ)
- 北大百炼1004 Financial Management 题解
- Oracle表数据误删恢复
- 用c实现的简单linux shell