解决Glide4.x上的crossFade无法生效

问题出现场景

因为旧项目用的是Glide4.0,新项目升级到Glide4.8以后,加载的渐变效果crossFade在部分组件失效(RoundImageView,然而实际上在我一开始网上搜索的时候,大部分人遇到这个情况也是在这个View上)

结果差异

  • 普通ImageView渐变效果仍然生效
  • RoundImageView以及部分自定义View失效

CrossFade的作用过程

glide设置图片到目标ImageView

  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition 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显示渐变

后续

其实这个问题在网上挂了一大堆,我也查找过程也一一看了不少,都没有一个很好的解释或者良好的解决方案(也许是我查的姿势不对?),实际上只要稍微看一下源码,发现还是不难理解

你可能感兴趣的:(解决Glide4.x上的crossFade无法生效)