前言:或许你身边一个不起眼的小人物就是某个领域的超级大神~不要轻易地侮辱任何一个人的错误,因为你也曾范错过
系列文章:
Android自定义控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268
上篇给大家讲了在setColorFilter中使用ColorMatrix的过程,其实setColorFilter除了使用ColorMatrix还有其它的用法,这节我们就具体来看看setColorFilter的用法。
在本篇文章中,你将学到两个实例:
public ColorFilter setColorFilter(ColorFilter filter)参数是传入ColorFilter的对象,其实ColorFilter是一个空对象,其中什么也没有:
public class ColorFilter { int native_instance; /** * @hide */ public int nativeColorFilter; protected void finalize() throws Throwable { try { super.finalize(); } finally { finalizer(native_instance, nativeColorFilter); } } private static native void finalizer(int native_instance, int nativeColorFilter); }但是ColorFilter派生了几个子类,分别是:
下面我们分别来讲讲各个子类的用法及效果
ColorMatrixColorFilter(ColorMatrix matrix) ColorMatrixColorFilter(float[] array)在这里可以直接传入一个ColorMatrix对象,也可以直接传入一个色彩矩阵。我们知道ColorMatrix对应的也是一个色彩矩阵。
canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint); canvas.translate(510, 0); // 生成色彩矩阵 ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 1/2f,1/2f,1/2f,0,0, 1/3f,1/3f,1/3f,0,0, 1/4f,1/4f,1/4f,0,0, 0,0,0,1,0 }); mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint);效果图如下:
public LightingColorFilter(int mul, int add)这里有两个参数,mul是乘法multiply的缩写,add是加法的意思。mul和add取值都是0xRRGGBB,分别对应R、G、B颜色,注意哦,这里是没有透明度A的,透明度在这里是不起作用的,LightingColorFilter只针对RGB色值起作用
结果R值 = (r*mul.R+add.R)%255; 结果G值 = (g*mul.G+add.G)%255; 结果B值 = (b*mul.B+add.B)%255;前面我们讲了mul和add的取值都是0xRRGGBB类型的值,即mul和add中都是包含了R、G、B分量的;
结果R值 = (r*mul.R+add.R)%255;作用LightingColorFilter(mul, add)效果后的R值等于,原来的r值乘以mul.R,然后再加上add.R做为最终结果。因为颜色值要的取值范围在0-255,所以要把结果对255取余,得到最终结果。
我们可以在点击时让它变成绿色,这要怎么做呢?直接使用LightingColorFilter把其它颜色都过滤掉,只显示绿色就可以了:
public class MyView extends View { private Paint mPaint; private Bitmap mBmp; public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mBmp = BitmapFactory.decodeResource(getResources(),R.drawable.btn); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setAntiAlias(true); int width = 500; int height = width * mBmp.getHeight()/mBmp.getWidth(); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(0,550); mPaint.setColorFilter(new LightingColorFilter(0x00ff00,0x000000)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); } }这段代码中最重要的就是这句:
mPaint.setColorFilter(new LightingColorFilter(0x00ff00,0x000000));这里把mul参数设置为0x00ff00,即把绿色显示出来,把R和B过滤掉。而add参数全部设置为0,即没有对原始图像色彩做任何改变
好像这样会有点问题,因为普通我们在点击按钮的时候,不可能会直接把它改变成另一个颜色,而只是增加它的颜色深浅值。比如下面我们增强颜色的蓝色值,将整个图片变得更蓝
protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setAntiAlias(true); int width = 500; int height = width * mBmp.getHeight()/mBmp.getWidth(); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new LightingColorFilter(0xffffff,0x0000f0)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); }我们在设置LightingColorFilter使用了:
mPaint.setColorFilter(new LightingColorFilter(0xffffff,0x0000f0));mul参数设置为0xffffff,即没有对颜色做任何改变;add参数设置为0x0000f0,即在每个像素的蓝色值在原来基础上增加0xf0,让原来的图像变得更蓝;这样会显得整个图片的颜色更深。更像按压后的效果。
public PorterDuffColorFilter(int srcColor, PorterDuff.Mode mode)其中有两个参数:
Mode.CLEAR Mode.SRC Mode.DST Mode.SRC_OVER Mode.DST_OVER Mode.SRC_IN Mode.DST_IN Mode.SRC_OUT Mode.DST_OUT Mode.SRC_ATOP Mode.DST_ATOP Mode.XOR Mode.DARKEN Mode.LIGHTEN Mode.MULTIPLY Mode.SCREEN Mode.OVERLAY Mode.ADD有关这些混合模式,这里我们只简单的讲解一下具体效果,详细的算法会在后面详细讲解。
public class MyView extends View { private Paint mPaint; private Bitmap mBmp; public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mBmp = BitmapFactory.decodeResource(getResources(),R.drawable.dog); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setAntiAlias(true); drawPorterDuffFilter(canvas); } private void drawPorterDuffFilter(Canvas canvas){ int width = 500; int height = width * mBmp.getHeight()/mBmp.getWidth(); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY));//变暗 canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); } }效果图如下:
左侧是原图,右侧是与纯红色正片叠底后的效果。这些效果在PhotoShop中都是存在的
首先,准备两张图片
和
效果图如下:
在录相中给大家演示了通过Photoshop来改变混合模式的过程,录相中分别更改了Mode.DARKEN(变暗),Mode.LIGHTEN(变亮),Mode.MULTIPLY(正片叠底),Mode.OVERLAY(叠加),Mode.SCREEN(滤色)这五种效果,大家可以尝试,我们通过代码得到的效果是与PhotoShop中的模式相同的。但PhotoShop中要比我们中强大的多,除了这些模式以外,还有其它的一些模式是我们所没有的;当然,PhotoShop中的所有这些效果都是可以通过ColorMetrix完成的,但前提是数学和色彩设计知识都要很棒才行哦。但Mode.ADD(饱和度)相加在Photoshop中是没有的。
下面我通过代码把这几个效果给大家分别画出来:
效果图如下:
对应代码如下:
public class MyView extends View { private Paint mPaint; private Bitmap mBmp; public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mBmp = BitmapFactory.decodeResource(getResources(),R.drawable.dog); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setAntiAlias(true); drawPorterDuffFilter(canvas); } private void drawPorterDuffFilter(Canvas canvas){ int width = 500; int height = width * mBmp.getHeight()/mBmp.getWidth(); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.ADD));//饱和度相加 canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DARKEN));//变暗 canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(-550,550); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.LIGHTEN));//变亮 canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY));//正片叠底 canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(-550,550); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.OVERLAY));//叠加 canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SCREEN));//滤色 canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); } }在这里大家不必理解PorterDuff.Mode的具体算法,只需要知道应用哪个模式,对应效果是怎样的就可以了。
private void drawPorterDuffFilter(Canvas canvas){ int width = 500; int height = width * mBmp.getHeight()/mBmp.getWidth(); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.CLEAR)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(-550,550); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.XOR)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); }得到的效果图如下:
在效果图中,只画出了原始图,另外两个图连个毛也没看到,没看到就对了,因为在应用Mode.CLEAR和Mode.XOR后,图像就会被完全清空了,当然什么也不会看到
第二组:目标图像模式
在Mode模式中,有一组DST相关的模式,DST所代表的意义就是被应用模式的图像,即我们这里的小狗图片。这些模式有:Mode.DST、Mode.DST_IN、Mode.DST_OUT、Mode.DST_OVER、Mode.DST_ATOP下面我们来看看他们的效果:
private void drawPorterDuffFilter(Canvas canvas){ int width = 500; int height = width * mBmp.getHeight()/mBmp.getWidth(); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DST)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(-550,550); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DST_IN)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DST_OUT)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(-550,550); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DST_OVER)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DST_ATOP)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); }效果图如下:
从效果图中可以看到,除了Mode.DST_OUT显示完全透明图片以外,其它全部显示目标图像;
所以这几个模式在PorterDuffColorFilter的实际应用中,并没什么用。
第三组:源图模式
在Mode模式中,有一组SRC相关的模式,SRC表示的颜色值所代表的图像,这些模式有:Mode.SRC、Mode.SRC_IN、Mode.SRC_OUT、Mode.SRC_OVER、Mode.SRC_ATOP下面我们来看看他们的效果:
private void drawPorterDuffFilter(Canvas canvas){ int width = 500; int height = width * mBmp.getHeight()/mBmp.getWidth(); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(-550,550); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_OUT)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(-550,550); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_OVER)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(550,0); mPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); }同样是通过位移把相关的模式所对应的图像一个个画出来,效果图如下:
从效果图中可以看出,除了Mode.SRC_OUT显示完全透明图片以外,其它全部显示源图像;
利用这个特性,我们可以在不同情况下,改变一个纯色图标的颜色。这个也是V4包中DrawableCompat类添加的一个setLint()函数所使用实现方法
setTint(Drawable drawable, int tint)这个函数用于将一个图像设指为指定的颜色,比如下面的效果:
即最左边是一原图,后面都是指定的各个颜色,利用setTint就可以把一个图片渲染为不同的颜色,这样就可以支持多主题,在不同的风格和不同的情境下使用不同的颜色的图片。由于仅使用一个图片就可以实现多个主题,就不必再引入多个颜色的切图,就可以在一定程度上缩小包的大小。
我们不必引入V4包,仅仅通过PorterDuffColorFilter就可以实现setTint的功能:
private void drawPorterDuffFilter(Canvas canvas){ int width = 100; int height = width * mBmp.getHeight()/mBmp.getWidth(); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(150,0); mPaint.setColorFilter(new PorterDuffColorFilter(0xffff00ff, PorterDuff.Mode.SRC)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(150,0); mPaint.setColorFilter(new PorterDuffColorFilter(0xff00f0ff, PorterDuff.Mode.SRC_ATOP)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(150,0); mPaint.setColorFilter(new PorterDuffColorFilter(0xfff0f0ff, PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(150,0); mPaint.setColorFilter(new PorterDuffColorFilter(0xffffff00, PorterDuff.Mode.SRC_OVER)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); canvas.translate(150,0); mPaint.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.SRC_ATOP)); canvas.drawBitmap(mBmp,null,new Rect(0,0,width,height),mPaint); }效果图如下:
从效果图中可以看到,SRC相关的模式,只有Mode.SRC_ATOP和SRC_IN能够实现SetTint的功能,其它的是不行的。这里先记着就可以了,后面地讲原理时会具体讲原因。
所以这里的一个应用就是通过PorterDuffColorFilter的Mode.SRC_ATOP或SRC_IN模式实现SetTint()的功能;
有些同学可能会讲,这个功能是不是可以通过ColorMatrix来实现?当然是可以的,比如我们要将原图标改成第三个效果,即颜色为0xff00f0ff,所对应的矩阵为:
ColorMatrix matrix = new ColorMatrix(new float[]{ 0,0,0,0,0, 0,0,0,0,240, 0,0,0,0,255, 0,0,0,1,0 });可不可以看出其中的门道?把原图像中的R、G、B全部置为0,然后我们通过每行最后的那个位移参数来指定我们想指定的RGB色。
如果本文有帮到你,记得加关注哦
源码下载地址:http://download.csdn.net/detail/harvic880925/9503651
请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/51253944 谢谢
如果你喜欢我的文章,那么你将会更喜欢我的微信公众号,将定期推送博主最新文章与收集干货分享给大家(一周一次)