1. 背景
在使用Glide4.X
的时候,经常会使用到图片变换的情况,都是网上搜索一番,Ctrl + C
+ Ctrl + V
,没有系统地去看过这一块东西,网上的资料也很零散,有时候遇到一些较复杂的情况,得搜索好久才能得到自己想要的结果。出现这个痛点后,现准备针对Transformation
罗列记录一下。
本文Glide版本为4.13.2
implementation 'com.github.bumptech.glide:glide:4.13.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
文中的布局是一个固定宽高300*300
的ImageView
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="300dp"
android:layout_height="300dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
正常显示photo1
效果如下
2. Transformation是什么
Transformation(转换器),这个类可以说是 Glide 压缩裁剪图片的核心类,因为该类功能就是依据要求输出的宽高对原始资源进行压缩裁剪之类的转换
public interface Transformation<T> extends Key {
/**
* 转换原始资源并返回转换后的资源对象
*/
Resource<T> transform(@NonNull Context context, @NonNull Resource<T> resource,
int outWidth, int outHeight);
}
3. Glide自带的Transformations
我们使用Android Studio
自带的Hierarchy
工具,可以查看到,实现Transformations
接口的类总共有这些
Hierarchy
工具的具体使用,详见我的另一篇博客 : Android Studio 使用 自带的Hierarchy查看类/方法/调用的层级关系
3.1 BitmapTransformation
BitmapTransformation
有很多子类,这里是我们关注的重点
3.1.1 CenterCrop、fitCenter和CenterInside
其中,Glide中的CenterCrop
、fitCenter
、CenterInside
和ImageView的scale type
有对应关系,对照关系如下
Glide | ImageView的scaleType |
---|---|
CenterCrop | centerCrop |
fitCenter | fitCenter |
CenterInside | centerInside 和 fitXY |
关于
ImageView scaleType
可以查看这篇文章 Android ImageView 的scaleType 属性图解
从代码中也可以看出这种对照关系 RequestBuilder#into()
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
3.1.2 CircleCrop
这个就是对图片裁剪为圆形
Glide.with(this)
.load(R.drawable.photo1)
.circleCrop()
.into(imageView)
效果如下
3.1.3 Rotate
这个就是对图片进行旋转操作
Glide.with(this)
.load(R.drawable.photo1)
.transform(Rotate(90))
.into(imageView)
3.1.4 RoundedCorners
这个是对图片进行圆角操作
Glide.with(this)
.load(R.drawable.photo1)
.transform(RoundedCorners(ConvertUtils.dp2px(30F)))
.into(imageView)
效果如下
3.1.5 GranularRoundedCorners
这个是当上下左右四个圆角值不一样的时候,对每个圆角的值进行定义
val radius30 = ConvertUtils.dp2px(30F).toFloat()
val radius5 = ConvertUtils.dp2px(5F).toFloat()
Glide.with(this)
.load(R.drawable.photo1)
.transform(GranularRoundedCorners(radius30, radius5, radius30, radius5))
.into(imageView)
效果如下
3.2 MultiTransformation 多重变换
默认情况下,每个 transform()
调用,或任何特定转换方法fitCenter(), centerCrop(), bitmapTransform()
的调用都会替换掉之前的变换。
如果想在单次加载中应用多个变换,需要使用使用 MultiTransformation
类。
Glide.with(this)
.load(R.drawable.photo1)
.transform(MultiTransformation(CenterCrop(),Rotate(90)))
.into(imageView)
效果如下
3.3 其他自带的Transformation
3.3.1. UnitTransformation
不做任何处理,直接返回
@NonNull
@Override
public Resource<T> transform(
@NonNull Context context, @NonNull Resource<T> resource, int outWidth, int outHeight) {
return resource;
}
3.3.2 DrawableTransformation
将Bitmap转化为Drawable,在源码里有用到,我们一般不会去调用。
3.3.3 BitmapDrawableTransformation
注解上说已弃用,建议使用DrawableTransformation
4. Transformation扩展 : glide-transformations
Github上有一个Glide的Transformation
库,glide-transformations,提供了一些额外的Transformation
需要添加如下依赖
implementation 'jp.wasabeef:glide-transformations:4.3.0'
// 如果想使用GPU Filter,需要这个依赖,对应着文中的4.13-4.22部分
implementation 'jp.co.cyberagent.android:gpuimage:2.1.0'
4.1 Mask
Glide.with(context)
.load(R.drawable.photo1)
.apply(overrideOf(266.px, 252.px))
.apply(bitmapTransform(MultiTransformation<Bitmap>(CenterCrop(),
MaskTransformation(R.drawable.mask_starfish))))
.into(holder.image)
4.2 NinePatchMask
Glide.with(context)
.load(R.drawable.photo1)
.apply(overrideOf(300.px, 200.px))
.apply(bitmapTransform(MultiTransformation<Bitmap>(CenterCrop(),
MaskTransformation(R.drawable.mask_chat_right))))
.into(holder.image)
4.3 RoundedCorners
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(RoundedCornersTransformation(120, 0,
RoundedCornersTransformation.CornerType.DIAGONAL_FROM_TOP_LEFT)))
.into(holder.image)
4.4 CropTop
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropTransformation(300.px, 100.px, CropType.TOP)))
.into(holder.image)
4.5 CropCenter
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropTransformation(300.px, 100.px, CropType.CENTER)))
.into(holder.image)
4.6 CropBottom
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropTransformation(300.px, 100.px, CropType.BOTTOM)))
.into(holder.image)
4.7 CropSquare
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropSquareTransformation()))
.into(holder.image)
4.8 CropCircle
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropCircleTransformation()))
.into(holder.image)
4.9 CropCircleWithBorder
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(
CropCircleWithBorderTransformation(Utils.toDp(4), Color.rgb(0, 145, 86))))
.into(holder.image)
4.10 Grayscale
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(GrayscaleTransformation()))
.into(holder.image)
4.11 BlurLight
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(BlurTransformation(25)))
.into(holder.image)
4.12 BlurDeep
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(BlurTransformation(25, 8)))
.into(holder.image)
4.13 Toon
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(ToonFilterTransformation()))
.into(holder.image)
4.14 Sepia
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(SepiaFilterTransformation()))
.into(holder.image)
4.15 Contrast
Glide.with(context)
.load(R.drawable.check)
.apply(bitmapTransform(ContrastFilterTransformation(2.0f)))
.into(holder.image)
4.16 Invert
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(ContrastFilterTransformation(2.0f)))
.into(holder.image)
4.17 Pixel
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(PixelationFilterTransformation(20f)))
.into(holder.image)
4.18 Sketch
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(SketchFilterTransformation()))
.into(holder.image)
4.19 Swirl
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(
SwirlFilterTransformation(0.5f, 1.0f, PointF(0.5f, 0.5f))).dontAnimate())
.into(holder.image)
4.20 Brightness
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(BrightnessFilterTransformation(0.5f)).dontAnimate())
.into(holder.image)
4.21 Kuawahara
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(KuwaharaFilterTransformation(25)).dontAnimate())
.into(holder.image)
4.22 Vignette
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(VignetteFilterTransformation(PointF(0.5f, 0.5f),
floatArrayOf(0.0f, 0.0f, 0.0f), 0f, 0.75f)).dontAnimate())
.into(holder.image)
5. 自定义Transformation
如果常用的Transformation
满足不了我们的需要,也可以自定义Transformation
如果只需要变换 Bitmap,最好是从继承 BitmapTransformation
开始。BitmapTransformation
为我们处理了一些基础的东西,例如,如果变换返回了一个新修改的 Bitmap ,BitmapTransformation
将负责提取和回收原始的 Bitmap。
比如,我们自己去实现一个旋转图片的Transformation
class RotateTransformation(private val angle: Float) : BitmapTransformation() {
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
}
override fun transform(
pool: BitmapPool,
toTransform: Bitmap,
outWidth: Int,
outHeight: Int
): Bitmap {
val matrix = Matrix()
matrix.postRotate(angle)
return Bitmap.createBitmap(
toTransform,
0,
0,
toTransform.width,
toTransform.height,
matrix,
true
)
}
}
进行使用
Glide.with(this)
.load(R.mipmap.photo1)
.apply(bitmapTransform(RotateTransformation(90F)))
.into(imageView)
效果如下