Android中使用背景色Alpha值遇到的一个坑
前言
Android通过设置Alpha值图片淡化、透明度大家应该都知道,下面是段简单的示例代码:
Viewv=findViewById(R.id.img_layout); v.getBackground().setAlpha(77);//设置背景图片透明度;0~255透明度值
以上是个简单的介绍,但本文介绍的是公司项目一个留了很久的bug,尝试找了很多次原因都没有头绪。
这个bug是这样的:
定义了一个主题色为例如#FF0000,很多界面控件都用了这个颜色。可是这个颜色在app使用过程中用着用着就会出现变成了透明的情况,而且出现透明之后,所有使用这个颜色的控件都会变成透明。
更奇怪的是,重启应用会恢复这个问题,但是操作一会儿又会出现。
项目有个随着页面滚动标题栏从透明过渡到主题色的界面实现,类似于Design库中AppBar的那种效果。实现方法是这样的:
//滚动监听器伪代码 someParams->{ //... view.getBackground().setAlpha(percent); //... }
今天「代码级复用」这一feature时,发现把bug也引入了新项目,才发现这个实现的问题之所在……
首先,view.getBackground()获得的是一个ColorDrawable,然后给这个ColorDrawable设置Alpha值的话,会影响所有设置background为这个颜色的背景色的Alpha值。
然后就写了个小demo验证了一下这个说法,虽然不是立即生效的,然后返回退出应用后,两个相同颜色背景的view,改变其中一个确实会影响到另一个。
当时反应就是:WTF?难不成全局的相同颜色的Drawable都是同一个对象?不过很快打印了一下background的drawable对象验证了并不是这样——虽然这些view获得的ColorDrawable的Alpha值都相同,但hashcode都是不同的。
所以我更倾向于这是Android内存优化带来的bug,即使这个颜色在定义时就有Alpha值,在修改后也会被忽略,并影响到其他的view。该问题只在布局文件里设置background为一个color的id或者值,或者setBackgroundResource为一个color时存在。如果使用newColorDrawable(int)来构造一个使用相同颜色值的对象则不受影响,我目前也正是使用这个方法来躲避掉这个feature。
UPDATE:
发现文档里有这个方法,验证了之前的说法,从同一资源加载的drawable确实会共享状态,不过有一个mutate方法来禁用这一特性。文档如下:
Drawablemutate()
Makethisdrawablemutable.Thisoperationcannotbereversed.Amutabledrawableisguaranteedtonotshareitsstatewithanyotherdrawable.Thisisespeciallyusefulwhenyouneedtomodifypropertiesofdrawablesloadedfromresources.Bydefault,alldrawablesinstancesloadedfromthesameresourceshareacommonstate;ifyoumodifythestateofoneinstance,alltheotherinstanceswillreceivethesamemodification.CallingthismethodonamutableDrawablewillhavenoeffect.
翻译:
Drawablemutate()
让一个Drawable变为mutable的。这个操作是不可逆的。一个mutable的drawable可以保证不会分享自己的状态给其他drawable。当一个drawable是从resource加载的,在需要更改它状态时这个方法特别有用。在默认情况下,所有从相同resource的drawable的实例是共享一个通用状态的;如果你修改了其中一个的状态,所有其他的实例也会收到相同的改动。在一个已经是可变的drawable上调用该方法没有效果。
所以,上述代码只要在drawable获取之后,调用一下mutate()方法即可。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。