Glide centerCrop fitCenter和ImageView的scaleType的关系,互相影响的探讨

来源:互联网 发布:图解组合模式 java 编辑:程序博客网 时间:2024/05/17 21:06

转载请注明出处,谢谢http://blog.csdn.net/harryweasley/article/details/71526216

在使用Glide的过程中,你一定见过下面的代码方式:

        ImageView imageView = (ImageView) findViewById(R.id.image);        imageView.setScaleType(ImageView.ScaleType.FIT_START);        Glide.with(this).load("https://zhitu.isux.us/assets/img/imgSample/test-60.jpg").fitCenter().into(imageView);

ImageView有自己的scaleType,Glide又有自己的fitCenter或者centerCrop,那这两者的关系到底是怎么样的,是否会互相影响呢,本篇博客就来探讨这个问题的。

Glide提供了两个标准选项来处理图像的显示问题,一个是centerCrop一个是fitCenter:

CenterCrop

CenterCrop()是一个裁剪技术,即缩放图像让它填充到 ImageView 界限内并且裁剪额外的部分。ImageView 会被完全填充,但图像可能不会完整显示。

FitCenter

fitCenter() 是一个裁剪技术,即缩放图像让图像都测量出来等于或小于 ImageView 的边界范围。该图像将会完全显示,但可能不会填满整个 ImageView。

看本篇博客开头的那三句代码,我们先看Glide源码的fitCenter方法:
com.bumptech.glide.DrawableRequestBuilder

public DrawableRequestBuilder<ModelType> fitCenter() {        return transform(glide.getDrawableFitCenter());    }public DrawableRequestBuilder<ModelType> transform(Transformation<GifBitmapWrapper>... transformation) {        super.transform(transformation);        return this;    }

DrawableRequestBuilder的transform调用父类的transform,继续看父类的源码:
com.bumptech.glide.GenericRequestBuilder

/**     * Transform resources with the given {@link Transformation}s. Replaces any existing transformation or     * transformations.     * 用给定的Transformation转换资源。替换任何已存在的transformation或者transformations。⭐1     * @param transformations the transformations to apply in order.     * @return This request builder.     */    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform(            Transformation<ResourceType>... transformations) {        //这个变量之后要用到,请留意 ⭐2        isTransformationSet = true;        if (transformations.length == 1) {            transformation = transformations[0];        } else {            transformation = new MultiTransformation<ResourceType>(transformations);        }        return this;    }

我们看到将fitCenter的对象glide.getDrawableFitCenter()加入到了transformation;同理,如果是centerCrop,那么会将glide.getDrawableCenterCrop()加入到transformtion,之后Glide会根据传入的transformtion以某个图片处理格式来从网络下载图片。

fitCenter源码先分析到这里,现在我们进入Glide的源码查看into方法都做了哪些操作,

com.bumptech.glide.GenericRequestBuilder

public Target<TranscodeType> into(ImageView view) {        Util.assertMainThread();        if (view == null) {            throw new IllegalArgumentException("You must pass in a non null View");        }        if (!isTransformationSet && view.getScaleType() != null) {            switch (view.getScaleType()) {                case CENTER_CROP:                    applyCenterCrop();                    break;                case FIT_CENTER:                case FIT_START:                case FIT_END:                    applyFitCenter();                    break;                //$CASES-OMITTED$                default:                    // Do nothing.            }        }        return into(glide.buildImageViewTarget(view, transcodeClass));    }

首先看这个判断 if (!isTransformationSet && view.getScaleType() != null)
由ImageView的源码可知,每一个ImageView都有个默认的fitCenter的scaleType,ImageView的源码:

 public ImageView(Context context) {        super(context);        initImageView();    }    public ImageView(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        this(context, attrs, defStyleAttr, 0);    }    public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,            int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        initImageView();        ...        }    private void initImageView() {         ...         //将FIT_CENTER设置为默认的scaleType         mScaleType = ScaleType.FIT_CENTER;         ...      }

我们可以看到,每个ImageView都会默认将 mScaleType = ScaleType.FIT_CENTER

由以上得知unview.getScaleType() != null一定为true,

这里的isTransformationSet 是不是很熟悉,没错,就是上面⭐2说的要用到的那个变量,

从这里可以看出如果Glide如果执行了centerCrop或者fitCenter,那么 if (!isTransformationSet && view.getScaleType() != null)里面的代码将不会执行。

那么如果Glide没有执行centerCrop和fitCenter,if (!isTransformationSet && view.getScaleType() != null)里面的代码将会执行,我们会看到,他根据传入的ImageView的scaleType做了两件事情,执行applyCenterCrop()或者applyFitCenter(),我们去源码中看看:

com.bumptech.glide.GenericRequestBuilder

 void applyCenterCrop() {        // To be implemented by subclasses when possible.    }    void applyFitCenter() {        // To be implemented by subclasses when possible.    }

我们看到是一个空方法,具体实现是在子类中实现的,那我们就去子类DrawableRequestBuilder中看看,源码如下:
com.bumptech.glide.DrawableRequestBuilder

 @Override    void applyFitCenter() {        fitCenter();    }    @Override    void applyCenterCrop() {        centerCrop();    }

看到这里有没有恍然大悟,从这里我们可以到一个结论,如果我们没有给Glide手动添加centerCrop和fitCenter方法,Glide会根据传入的ImageView的scaleType来自己去执行centerCrop或者fitCenter方法。(我知道你一定会说,scaleType不仅仅是CENTER_CROP,FIT_CENTER,FIT_START,FIT_END,这个我知道的哈,后面还会继续说的。)

你以为这就是ImageView的scaleType在Glide里的作用吗,错了,这个scaleType在最后将图片设置到ImageView还起了一次作用。
在Glide获取到图片资源,会执行ImageView的setImageDrawable将图片设置进去,源码如下:

com.bumptech.glide.request.target.GlideDrawableImageViewTarget

/**     * Sets the drawable on the view using     * {@link android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.     *     * @param resource The {@link android.graphics.drawable.Drawable} to display in the view.     */    @Override    protected void setResource(GlideDrawable resource) {        view.setImageDrawable(resource);    }

综上可以总结一个结论:ImageView的scaleType在Glide加载图片到ImageView的过程中至少起一次作用。

经过我的多次测试,得出一个结论,如果ImageView的scaleType不是centerCrop,并且Glide没有调用centerCrop方法,那么Glide从服务器获取的图片格式是fitCenter格式,最终设置到ImageView图片的格式,还要根据ImageView的scaleType才能确定。

不知道,你是否注意到⭐1的标志,那边的一个注释说明了一个问题,如果Glide同时执行了centerCrop和fitCenter方法,那么谁在后面,就以谁的格式下载图片。
打个比方,代码如下:

 Glide.with(this).load("https://zhitu.isux.us/assets/img/imgSample/test-60.jpg").fitCenter().centerCrop().into(imageView);

那么从网络下载到的图片是以centerCrop格式下载到的。

本篇博客最后,分析一下ImageView的8个scaleType:

CENTER 将图像置于视图中,但不执行缩放。 CENTER_CROP 缩放图像(保持图像的纵横比),使图像的尺寸(宽度和高度)都等于或大于视图的相应尺寸(减去填充)。所以会占满ImageView,但是可能会显示不完全图片 CENTER_INSIDE 缩小图像均匀(保持图像的纵横比),使图像的尺寸(宽度和高度)都等于或小于视图的对应尺寸(减去填充)。 FIT_CENTER 保持原图的纵横比计算一个比例,但是也要确保原图完全放入目标视图内, 至少一个轴(X或Y)将精确配合。 结果以目标视图为中心。默认属性 FIT_END 保持原图的纵横比计算一个比例,但是也要确保原图完全放入目标视图内, 至少一个轴(X或Y)将精确配合。END将结果对齐到目标视图右下边缘。 FIT_START 保持原图的纵横比计算一个比例,但是也要确保原图完全放入目标视图内, 至少一个轴(X或Y)将精确配合。 START将结果对齐到目标视图左上边缘。 FIT_XY 独立地缩放X和Y,使原图与目标完全匹配。 这可能会改变原图的宽高比。 MATRIX 绘制时使用图像矩阵进行缩放。

最后再次总结一下本篇博客:

Glide从网络下载到的图片,会按照两种格式来下载,一种是centerCrop,一种是fitCenter,一旦下载下来后,设置到ImageView的时候,还会根据ImageView的scaleType来确立图片位置。
如果Glide没有手动调用过centerCrop和fitCenter,那么Glide从网络下载的图片格式,由ImageView的scaleType决定,如果scaleType是center_crop,那么Glide以centerCrop下载图片,如果scaleType是 FIT_CENTER,FIT_START,FIT_END,那么Glide以fitCenter格式下载图片。不过根据我这边的测试结果发现,如果scaleType是CENTER,CENTER_INSIDE,MATRIX,Glide也是以fitCenter格式下载图片的。

参考文章:
https://developer.android.com/reference/android/widget/ImageView.ScaleType.html
https://futurestud.io/tutorials/glide-image-resizing-scaling
http://www.jianshu.com/p/96fc561eada1

1 0
原创粉丝点击