Tint这个东西主要是用来减小apk的体积的,比如我现在有一个textview,它的背景图片有两种,一种是获得焦点时显示的图片,另一个是失去焦点时显示的b图。这个需求相信你在开发的时候做过很多次了。我们通常会发现这种图a和图b除了颜色不同外其他都是一样的。但是当我们这样做的时候,我们通常会要求两张图片。如果要适配分辨率,很有可能图片会比较多,而且切换的时候会重新加载位图,效率会下降很多。于是谷歌给出了一套解决方案,就是tint。他的目的是,当你发现这样的需求时,只需要在apk中放一张图片就可以了。当你需要改变背景图片的颜色时,可以使用Tint!下面就简单说说,tint的使用方法和需要注意的地方。首先,我们定义一个简单的布局文件:我们发现两个imageview都引用了同一个drawable资源,在studio的xml编辑界面中,我们可以清楚的看到图片的颜色是黑色的,对吧!那么现在我们要改一下,我们要把iv1imageview的背景色改成绿色!我们想当然的写成这样:iv1=(ImageView)this.findViewById(R.id.iv1);iv2=(ImageView)this。findViewById(R.id.iv2);finalDrawableoriginBitmapDrawable=getResources().getDrawable(R.drawable.ic_account_circle_black_18dp);iv1.setImageDrawable(tintDrawable(originBitmapDrawable,ColorStateList.valueOf(Color.GREEN)));应该很容易理解,正确的?代码不解释。但是我们运行之后发现,两者都变绿了!回顾我们的代码,我们应该能够理解两个imageviews引用同一个drawable。由于它是可绘制对象,系统必须优化资源。在内存中复制这两个可绘制对象!还记得我们之前讲过的位图优化吗?http://www.cnblogs.com/punkisnotdead/p/4881771.html和这个Attributes中的inBitmap效果一样。不明白的可以看看下图就明白了:所以才会出现上面的情况。您修改了公共变量,因此两个图都会受到影响。解决方法其实很简单:finalDrawableoriginBitmapDrawable=getResources().getDrawable(R.drawable.ic_account_circle_black_18dp).mutate();修改后看看:你看,这样搞完就一切正常了。那么有人要问了,搞什么鬼,你是不是破坏了谷歌给我们的图片内存优化方案?其实,这种担心是大可不必的。这个http://android-developers.blogspot.hk/2009/05/drawable-mutations.html这个地址会告诉你,其实我们只是单独取出内存受影响的部分,其他没有影响的部分受影响的仍然是共享数据!也就是说,我们的内存会另外存储一些纯标志位,类似于状态值。大部分内存仍然是公共的!那么来吧,让我们看下一个关于editext的例子。可以看到这个edittext的颜色是这样的。现在让我们修改一下这个edittext的背景色);背景色修改成功,但是光标的颜色没有变,很不协调。有人说我们可以利用这个xml属性来修改。当然,这个方法确实可以,但是你要是这样做的话,我们又需要重新添加资源文件,这不是有违我们的本色吗?所以我们得想办法突破这个地方。其实很多人都能想到方法。对于Android没有提供给我们的API,比如那些私有函数,我们通常会通过反射来调用。这里也一样。稍微想一想就明白了。在这个地方,我们先通过反射获取到cursorDrawable,然后对其进行着色,然后在反射调用方法中进行设置。还好吗?首先,我们都知道,editext其实就是textview,那么我们先看看textview的源码,看看这个属性的名字是什么。经过一番努力,我在这里找到了它://虽然这些字段是特定于可编辑文本的,但它们并没有添加到编辑器中,因为//它们是由TextView的样式定义的并且是主题依赖的。intmCursorDrawableRes;还要看编辑器的源码,跟edittext密切相关:/***EditTextspecificdata,createdondemandwhenoneoftheEditorfieldsisused.*ahref="http://www.jobbole.com/members/57845349">@link#createEditorIfNeeded()}.*/privateEditormEditor;//注意这段代码属于editorfinalDrawable[]mCursorDrawable=newDrawable[2];有了这段代码,我们就知道如何编写其余的反射代码了。//参数是反映和修改游标的edittext对象privatevoidinvokeEditTextCallCursorDrawable(EditTextet){try{FieldfCursorDrawableRes=TextView.class.getDeclaredField("mCursorDrawableRes");//看源码知道这个变量是不公开的,所以我们需要设置这个可访问属性fCursorDrawableRes.setAccessible(true);//获取editext对象中mCursorDrawableRes属性的值。看源码知道这是一个int值intmCursorDrawableRes=fCursorDrawableRes.getInt(et);//下面的代码是通过获取mEditor对象,然后通过mEditor对象获取drawableFieldfEditor=TextView.class.getDeclaredField("mEditor");fEditor.setAccessible(true);Objecteditor=fEditor.get(et);Classclazz=editor.getClass();FieldfCursorDrawable=clazz.getDeclaredField("mCursorDrawable");fCursorDrawable.setAccessible(true);if(mCursorDrawableRes<=0){return;}//这里终于得到了默认主题下edittext的光标小图标drawableDrawablecursorDrawable=et.getContext().getResources().getDrawable(mCursorDrawableRes);if(cursorDrawable==null){return;}//既然已经有了这个drawble,那就修改它吧。DrawabletintDrawable=tintDrawable(cursorDrawable,ColorStateList.valueOf(Color.GREEN));//前面贴的mCursorDrawable源码可以知道这是一个二维数组。所以我们要构造一个全新的二维数组Drawable[]drawables=newDrawable[]{tintDrawable,tintDrawable};//然后把这个二维数组的值通过反射放到编辑器中!fCursorDrawable.set(editor,drawables);}catch(NoSuchFieldExceptione){e.printStackTrace();}catch(IllegalAccessExceptione){e.printStackTrace();}}***调用这个方法看看效果:很***对~~***tintDrawable这个方法是为了向后兼容用的。如果不考虑向后兼容的问题,可以使用系统自带的方法,这里就不过多介绍了。publicstaticDrawabletintDrawable(Drawabledrawable,ColorStateListcolors){finalDrawablewrappedDrawable=DrawableCompat.wrap(drawable);DrawableCompat.setTintList(wrappedDrawable,colors);returnwrappedDrawable;}当然你也可以使用http://andraskindler.com/blog/2015/tinting这里drawables方法来做向下兼顾:publicfinalclassTintedBitmapDrawableextendsBitmapDrawable{privateinttint;privateintalpha;publicTintedBitmapDrawable(finalResourcesres,finalBitmapbitmap,finalinttint){super(res,bitmap);this.tint=tint;this.alpha=Color.alphaT(tined);finalResourcesres,finalintresId,finalinttint){super(res,BitmapFactory.decodeResource(res,resId));this.tint=tint;this.alpha=Color.alpha(tint);}publicvoidsetTint(finalinttint){this.tint=tint;this.alpha=Color.alpha(tint);}@Overridepublicvoiddraw(finalCanvascanvas){finalPaintpaint=getPaint();if(paint.getColorFilter()==null){paint.setColorFilter(newLightingColorFilter(tint,0));油漆。setAlpha(alpha);}super.draw(canvas);}}
