Android着色器Tint怎么使用(android,tint,移动开发)

时间:2024-04-28 08:44:11 作者 : 石家庄SEO 分类 : 移动开发
  • TAG :

Tint 这个东西 主要用来减少apk体积的,比如说我现在有一个textview,他的背景图 有两种,一种是当获得焦点时显示的a图,另一种是 失去焦点时显示的b图。

相信大家开发的时候 这种需求做过很多次了,我们一般都会发现 这种a图和b图 除了颜色不一样,其他都是一样的,但是我们做的时候呢,通常是找ui要了两张图。

如果要适配分辨率的话 很有可能图片会更多,而且在切换的时候 因为是重新加载一次bitmap 效率也会下降很多。所以谷歌就给了一套解决方案 这个就是tint了。

他的目的就是当你发现有这种需求的时候,只需要 放一张图 在apk里即可,当你需要改变背景图的颜色的时候 就用Tint即可!

首先 我们定义一个简单的布局文件:

Android着色器Tint怎么使用

我们发现这2个imageview 都是引用的同样一个drawable资源,并且 在studio这个xml编辑界面里面 我们很明显的 能看出来 这个图片的颜色是黑色的 对吧!

那 现在 我们想改一下,想把iv1 这个imageview的 背景色 改成绿色的! 我们想当然的 当然会这么写:

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)));

应该很好理解对吧,代码就不解释了。但是我们运行以后发现:

Android着色器Tint怎么使用

卧槽 怎么2个都变绿色了!

回顾一下 我们的代码 我们应该能明白 2个imageview 都是引用的同样的一个drawable,要知道 既然是一个drawable,那系统肯定为了优化资源 把这2个drawable 在内存里的拷贝弄成了一份!

还记得 我们以前讲的bitmap优化那篇么?http://www.cnblogs.com/punkisnotdead/p/4881771.html 和这个里面的inBitmap 属性有异曲同工之妙,如果还不理解 你看下面的图就理解了:

Android着色器Tint怎么使用

所以才会造成上面的情况。你修改了共同变量,所以2个图就都被影响了。

解决方法 其实也很简单:

finalDrawableoriginBitmapDrawable=getResources().getDrawable(R.drawable.ic_account_circle_black_18dp).mutate();

修改以后 我们再看:

Android着色器Tint怎么使用

你看这么做就一切正常了。

那有人就要问了,卧槽 你这么做 不是把谷歌给我们做好的图片内存优化方案给损坏了么,其实这种担心是多余的,这个http://android-developers.blogspot.hk/2009/05/drawable-mutations.html

这个地址会告诉你 其实我们做 只是把单独的受到影响的那部分 内存给单独拿出来了,其他没受到影响的还是共享的数据!换句话说 我们内存里 会另外存放的就是一些纯的标志位 之类的 类似于状态值这种东西。

大部分的内存还是公用的!

然后接着来,我们看下一个例子 关于editext的。

Android着色器Tint怎么使用

你看这个edittext 的颜色是这样的。那现在我们来修改一下 这个edittext的背景色

et1=(EditText)this.findViewById(R.id.et);finalDrawableoriginBitmapDrawable=et1.getBackground();et1.setBackgroundDrawable(tintDrawable(originBitmapDrawable,ColorStateList.valueOf(Color.GREEN)));

Android着色器Tint怎么使用

背景色是修改成功了 但是这个光标的颜色 还没变 非常不协调, 有人又要说了 我们可以用:

Android着色器Tint怎么使用

这个xml 属性来修改呀,当然了这个方法确实是可以的 但是你想 你这么做的话 又要增加资源文件了,不是与我们的tint 背道而驰了么?

所以 这个地方 我们就要想办法 突破一下。其实很多人都能想到方法了,对于android 没有 提供给我们的api 比如那些private 函数,

我们通常都是通过反射的方法 去调用的。 这里也是一样,稍微想一下 我们就能明白, 这个地方 我们就先通过反射来获取到这个cursorDrawable

然后给他着色,然后在反射调用方法 给他set进去不就行了么?

首先我们都知道 editext 实际上就是textview,所以我们看一下textview 的源码 找找看 这个属性到底叫啥名字。经过一番努力发现 在这:

//Althoughthesefieldsarespecifictoeditabletext,theyarenotaddedtoEditorbecause//theyaredefinedbytheTextView'sstyleandaretheme-dependent.intmCursorDrawableRes;

并且我们要看下editor的源码 这是和edittext息息相关的:

/***EditTextspecificdata,createdondemandwhenoneoftheEditorfieldsisused.*See{<ahref="http://www.jobbole.com/members/57845349">@link</a>#createEditorIfNeeded()}.*/privateEditormEditor;//注意这段代码属于editorfinalDrawable[]mCursorDrawable=newDrawable[2];

有了这段代码 我们就知道 剩下反射的代码怎么写了。

//参数就是要反射修改光标的edittext对象privatevoidinvokeEditTextCallCursorDrawable(EditTextet){try{FieldfCursorDrawableRes=TextView.class.getDeclaredField("mCursorDrawableRes");//看源码知道这个变量不是public的所以要设置下这个可访问属性fCursorDrawableRes.setAccessible(true);//取得editext对象里的mCursorDrawableRes属性的值看源码知道这是一个int值intmCursorDrawableRes=fCursorDrawableRes.getInt(et);//下面的代码是通过获取mEditor对象然后再通过拿到的mEditor对象来获取最终我们的mCursorDrawable这个光标的drawableFieldfEditor=TextView.class.getDeclaredField("mEditor");fEditor.setAccessible(true);Objecteditor=fEditor.get(et);Class<?>clazz=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};//然后再通过反射把这个二维数组的值放到editor里面即可!fCursorDrawable.set(editor,drawables);}catch(NoSuchFieldExceptione){e.printStackTrace();}catch(IllegalAccessExceptione){e.printStackTrace();}}

***调用这个方法以后看一下效果:

Android着色器Tint怎么使用

***tintDrawable这个方法是用来向下兼容用的。你如果不考虑向下兼容的问题 用系统自带的方法 就可以了,这里就不做过多介绍了。

publicstaticDrawabletintDrawable(Drawabledrawable,ColorStateListcolors){finalDrawablewrappedDrawable=DrawableCompat.wrap(drawable);DrawableCompat.setTintList(wrappedDrawable,colors);returnwrappedDrawable;}

当然你也可以用以下方法来做向下兼容:publicfinalclassTintedBitmapDrawableextendsBitmapDrawable{

privateinttint;privateintalpha;publicTintedBitmapDrawable(finalResourcesres,finalBitmapbitmap,finalinttint){super(res,bitmap);this.tint=tint;this.alpha=Color.alpha(tint);}publicTintedBitmapDrawable(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));paint.setAlpha(alpha);}super.draw(canvas);}}
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Android着色器Tint怎么使用的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:小程序如何实现多进程下一篇:

10 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18