问题出现场景
因为旧项目用的是Glide4.0,新项目升级到Glide4.8以后,加载的渐变效果crossFade在部分组件失效(RoundImageView,然而实际上在我一开始网上搜索的时候,大部分人遇到这个情况也是在这个View上)
结果差异
- 普通ImageView渐变效果仍然生效
- RoundImageView以及部分自定义View失效
CrossFade的作用过程
glide设置图片到目标ImageView
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
按照上面的代码transition.transition去寻找CrossFade的代码,发现在DrawableCrossFadeTransition这个类中
@Override
public boolean transition(Drawable current, ViewAdapter adapter) {
Drawable previous = adapter.getCurrentDrawable();
if (previous == null) {
previous = new ColorDrawable(Color.TRANSPARENT);
}
TransitionDrawable transitionDrawable =
new TransitionDrawable(new Drawable[] { previous, current });
transitionDrawable.setCrossFadeEnabled(isCrossFadeEnabled);
transitionDrawable.startTransition(duration);
adapter.setDrawable(transitionDrawable);
return true;
}
乍一看,没有任何问题,构建了一个TransitionDrawable,里面有目标资源和一个透明的Drawable,ImageView在绘制的时候,会让TransitionDrawable通过切换他的两个Drawable的alpha值来达到渐变的效果
上面说了crossFade在我的项目存在差异,系统的ImageView是生效的,自定义的则失效,Glide的源码好像又没什么问题,那问题肯定出在了自定义View上,那么就复盘自己自定义的View(以下均已RoundImageView为例)
- 大家都知道要展示一个圆形的图片,从两方面着手,要么去处理Drawable,要么去处理View(别问为什么Glide自带处理Drawable,还要用RoundImageView,问就是自有用处)
处理View的方法
- canvas.clipPath
- canvas.drawCircle+paint.setShader
- canvas.drawBitmap+paint.setXfermode+canvas.drawCircle
处理Drawable的方法就不谈了,因为我是在View里处理(懒~的贴),采用了上述的第二种方法
RoundImageView里对资源的处理
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
获取当前的Drawable,构建一个Bitmap作为Shader来为paint着色,结合上面说的Glide返回的是一个TransitionDrawable,可知道得到的Shader获取的总是TransitionDrawable的第一个资源也就是那个透明Drawable,造成了CrossFade的失效
查看GitHub的版本更迭
可以看到在历史版本中,当previous为空的时候,也就是第一次设置图片的时候,其实是调用defaultAnimation.transition(current, adapter)来完成渐变的效果,这也解释了为什么我在glide4.0的时候渐变还是正常的,升级到4.8以后就部分失效的原因
解决方案
既然知道了Glide的版本变迁,想用回旧版本的渐变效果,只需要照猫画虎模仿就OK了
@Override
public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
if (iv instanceof RoundImageView && iv.getTag(R.id.view_glide_animate) == null) {
iv.clearAnimation();
AlphaAnimation animation = new AlphaAnimation(0F, 1F);
animation.setDuration(300);
iv.startAnimation(animation);
iv.setTag(R.id.view_glide_animate, true);
}
return false;
}
在Glide加载的回调中统一处理为AlphaAnimation显示渐变
后续
其实这个问题在网上挂了一大堆,我也查找过程也一一看了不少,都没有一个很好的解释或者良好的解决方案(也许是我查的姿势不对?),实际上只要稍微看一下源码,发现还是不难理解