使用装饰器模式动态设置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。

使用装饰器模式动态设置Drawable的ColorFilter的更多相关文章

  1. (十)装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  2. IOS设计模式之二(门面模式,装饰器模式)

    本文原文请见:http://www.raywenderlich.com/46988/ios-design-patterns. 由 @krq_tiger(http://weibo.com/xmuzyq) ...

  3. PHP设计模式笔记九:装饰器模式 -- Rango韩老师 http://www.imooc.com/learn/236

    装饰器模式(Decorator) 概述 1.装饰器模式可以动态地添加修改类的功能 2.一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法 3. ...

  4. 涉及模式之 装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  5. 深入探索Java设计模式(三)之装饰器模式

    装饰器模式使你可以在运行时使用类似于对象组成的技术来装饰类.这在我们希望实例化具有新职责的对象而无需对基础类进行任何代码更改的情况下尤其有用.本文是在学习完优锐课JAVA架构VIP课程—[框架源码专题 ...

  6. 十:装饰器模式(io流)

    定义:装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.                  这一个解释,引自百度百科,我们 ...

  7. PHP 装饰器模式

    装饰器模式:是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能. [装饰器模式中主要角色] 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这 ...

  8. 设计模式-装饰器模式(Decrator Model)

    文 / vincentzh 原文连接:http://www.cnblogs.com/vincentzh/p/6057666.html 目录 1.概述 2.目的 3.结构组成 4.实现 5.总结 1.概 ...

  9. php设计模式 装饰器模式

    装饰器模式,可以动态地添加修改类的功能. 一个类提供了一项功能,如果要修改并添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法.使用装饰器模式,仅需要在运行时添加一个装饰器对象即可 ...

随机推荐

  1. hdu 1387 Team Queue (链表)

    题目大意: 不同的人在不同的队伍里,插入链表的时候假设这个链表里有他的队友,就把它放到最后一个队友的最后.假设没有队友,就把它放到整个链表的最后面. 出链表的时候把第一个人拿出来. 思路分析: 要模拟 ...

  2. Windows环境下访问NFS(33篇Storage的文章)

    Windows环境下访问NFS 使用Solaris时,如果想在两台Solaris之间共享数据,那么你想到的最省事.最方便的方法肯定是nfs.但是现在的学生们的桌面,估计99%以上都是Windows,W ...

  3. Java Web Services (1) - 第1章 Web服务快速入门

    SCRIPTS_DIR=/Users/liuzhaofu/opus-dev/product/tools/devPRODUCT_DIR=/Users/liuzhaofu/opus-dev/product ...

  4. iPhone开发【一】从HelloWorld開始

    转载请注明出处,原文网址:http://blog.csdn.net/m_changgong/article/details/8013553 作者:张燕广 从经典的HelloWorld開始踏入iPhon ...

  5. 零基Android手机嵌入式开发培训课程

    亲爱的朋友,我这里有一组当然想和大家分享,假设有兴趣在这个过程中,可以加我QQ2059055336和我联系. 课程章节分布: 第一部分 嵌入式C与数据结构篇 (20讲) 第二部分ARM裸机开发篇 (4 ...

  6. sd nfrmtl

    http://www.zhihu.com/collection/24337307 http://www.zhihu.com/collection/24337259 http://www.zhihu.c ...

  7. TkinterGUI - 初识Tkinter

    前言 近期有写一个简单GUI程序的点子,具体写什么就不说了,但一个要求就是有跨平台的功能. 确切的讲,是我希望这个程序写好后能同时在Windows和Linux下运行,而且要方便随时修改. 对于编程语言 ...

  8. Android OpenGL ES 应用(二) 纹理

    上一篇讲了基础入门 OpenGL (一) ,这一次主要学习OpenGL 纹理基本学习总结 要是做复杂的OpenGL应用程序,一定会用到纹理技术.纹理说白了就是把图片或者视频图像绘制到OpenGL空间中 ...

  9. [WebGL入门]十,矩阵计算和外部库

    注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:],另外,鄙人webgl研究还不够深入,一些专业词语,假设翻译有误,欢迎大家指 ...

  10. hdu1495(bfs)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1495 题意:有三个杯子,开始时第一个杯子装满水(体积为a),倒来倒去,得到其中2个杯里的水的体积都为a ...