Android中BitmapDrawable的一个bug

来源:互联网 发布:mac打开终端的快捷键 编辑:程序博客网 时间:2024/06/09 23:08

经常使用BitmapDrawable的人要小心了,BitmapDrawable放在StateListDrawable中的时候使用enterFadeDuration/exitFadeDuration可能会导致图片显示不出来的问题。

问题重现:

1. 定义一个StateListDrawable,即用selector定义一个Drawable,并且使用enterFadeDuration:

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"    android:enterFadeDuration="@android:integer/config_shortAnimTime">    <item android:state_enabled="false"        android:drawable="@drawable/button_disabled" />    <item android:drawable="@drawable/button_normal" /></selector>

2. 在Activity中如下使用这个Button:

    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        LinearLayout view = new LinearLayout(this);        final Button btn1 = new Button(this);        final Button btn2 = new Button(this);        btn1.setText("Button1");        btn1.setEnabled(false);        btn1.setBackgroundResource(R.drawable.button);        btn2.setText("Button2");        btn2.setBackgroundResource(R.drawable.button);        view.addView(btn1);        view.addView(btn2);        setContentView(view);        btn1.post(new Runnable() {            @Override            public void run() {                btn1.setEnabled(true);                StateListDrawable d = (StateListDrawable) btn1.getBackground();                BitmapDrawable bd = (BitmapDrawable) d.getCurrent();                Log.e("xxx", "alpha=" + bd.getPaint().getAlpha());                btn1.setVisibility(View.GONE);                btn2.invalidate();            }        });    }

从Log中可以看到,btn1当前的Drawable的alpha值并不是255,而是0~255之间的一个数值。而btn2的显示状态显然不对,因为它用Drawable的alpha值跟btn1一样,也不是255。

出问题的界面

如果此时触摸一下btn2,就会让btn2恢复成正常的显示状态。

正常的界面

上面的代码仅仅是为了重现这个问题,一般来说,真实的代码远比这个逻辑复杂,更加不容易发现问题所在。问题往往出现这样的时候:

1)StateListDrawable里使用了BitmapDrawable,并且使用fadeDuration(或直接调用了BitmapDrawable的setAlpha()函数)。

2)某一个使用这个Drawable的元素在做alpha动画的时候被隐藏或其他原因导致动画停止,alpha并没有还原。

3)或者,另一个使用这个Drawable的元素在另一个使用该Drawable的元素动画时被重绘。

其实,这个问题的根本原因是BitmapDrawable的Alpha值是同一个进程中所有相同的Bitmap的BitmapDrawable共用的。同样共用的属性还有:ColorFilter, Gravity, AntiAlias, Filter, Dither, TileModeX, TileModeY等,所以,操作这些属性的时候需要特别考虑是不是有其他的BitmapDrawable还需要使用他们。

另外,NinePatchDrawable不会有这个问题,因为NinePatchDrawable的alpha属性并不共用。

当然,要解决alpha值导致显示有问题也比较容易,那就是在显示btn2的时候,多调用一次jumpDrawablesToCurrentState()即可,或者,在设置btn2的背景的时候,不要用resource id,而是load成drawable,先调用drawable的mutate()函数,再设置成btn2的背景。要真正解决这个问题,只能期望android在BitmapDrawable中对每一个实例不共用上面提到的信息。

原创粉丝点击