README
本文对Glide - transformations进行简单的使用说明
Glide - transformations是Android平台一款优秀的图片处理工具
Github地址为:https://github.com/wasabeef/glide-transformations
本文所用到的代码地址:https://github.com/nikolajohn/GlideTransformationDemo
添加Glide依赖
首先在你的Android Studio里新建一个Android项目
然后打开这个文件
打开以后,加上这句话
implementation 'jp.wasabeef:glide-transformations:3.3.0'
就像这样
然后,在你的当前包下面,新建一个java 类,叫Utils
这个类的代码可以这样写
package cn.edu.zju.glidetest;
import android.content.Context;
public class Utils {
public static int dip2px(Context context, float dp) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
}
什么意思呢?其实看函数的名字就知道了,相当于一个量纲的转化
具体为什么要有这样一个转化,以及转化的代码为什么要这样写
可以查看这篇文章: https://blog.csdn.net/arui319/article/details/6777133?utm_source=blogxgwz0
添加RecycleView依赖
接下来,还是回到app目录下的gradle文件里
就是这里
添加如下代码
implementation 'com.android.support:recyclerview-v7:28.0.0'
添加完成后,就是这样的
添加RecycleView控件
接下来,打开MainActivity的布局文件(XML文件)
先把不用的删掉
然后添加RecycleView的控件,代码如下
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
就像这样
这里,RecycleView控件的id,你可以命名为list,也可以命名为recycler_view
因为你的RecycleView控件并不是内置在系统的SDK中,所以用的时候,需要把完整的包的路径都写出来,而不是像LinearLayout那种,前面没有完整的包名
添加item布局文件
接下来,新建一个Layout文件,这个用于存放你的每一个条目的布局,就叫layout_list_item
这个我们就这样写
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<ImageView
android:id="@+id/image"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:cropToPadding="false"
android:scaleType="fitCenter"
app:layout_constraintBottom_toTopOf="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
</android.support.constraint.ConstraintLayout>
做好之后就是这样的
适配器
接下来,你需要为你的RecycleView准备适配器
那么什么是适配器呢,这个我们看了后面的代码,相信你就会有自己的理解了
新建适配器类的方法很简单,和上面说过的是一样的,这个类的名字就叫做MainAdapter
因为你的这个适配器(Adapter)是针对RecycleView的,所以你需要让这个适配器继承自RecycleView.Adapter这个类,写好之后就像上面这样
此外,我们还需要将泛型指定为MainAdapter.ViewHolder,其中的ViewHolder就是我们在MainAdapter中定义的一个内部类
这个类的构造函数就这样写
第一个参数是你的上下文,这个是常规套路,一般都会有这样的一个context参数
第二个参数是一个List,List中的每一个数据的类型都是Type(这个我们后面再定义,你可以先理解成这就是一个我们自己定义的数据类型),这个数组的名字就叫做dataSet
刚刚我们提到了,需要在这里加一个内部类,如图所示
首先ViewHolder肯定是需要继承自RecyclerView.ViewHolder的
ViewHolder内部的代码其实很简单,写法也是很固定的
首先定义一下,你在每个item布局中用到的东西,比如我们之前用到的是一个ImageView和一个TextView,因此这里就这样定义即可
他的构造函数也很简单,就是把那些layout里的控件找一下就好,这些代码都是常规套路
然后你在你的MainAdpter中定义私有的数据类型,这个也是常规套路了
接下来看一下onCreateViewHolder函数
这个函数的写法还是比较固定的,但是有一点需要注意的是,如果你用上面的这种写法,你必须在MainAdapter里定义私有成员变量context,然后在MainAdapter的构造函数里面赋值一下,就像这样
如果你上面这两句话没有写,那么你的onCreateViewHolder函数应该这样写
@Override public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_list_item, parent, false);
return new ViewHolder(v);
}
你不这样写,IDE是会报错的
onBindViewHolder
接下来是一个非常重要的函数onBindViewHolder
在做这个函数之前,我们先把一些图片资源加载进来,加载的方式很简单,只要把图片放到你的mipmap文件夹里就好(图片的资源我会放在附件里)
接下来分析这个onBindViewHolder函数,先看代码
@Override public void onBindViewHolder(MainAdapter.ViewHolder holder, int position) {
switch (dataSet.get(position)) {
case Mask: {
int width = Utils.dip2px(context, 266.66f);
int height = Utils.dip2px(context, 252.66f);
Glide.with(context)
.load(R.mipmap.check)
.apply(overrideOf(width, height))
.apply(bitmapTransform(new MultiTransformation<>(new CenterCrop(),
new MaskTransformation(R.mipmap.mask_starfish))))
.into(holder.image);
break;
}
case NinePatchMask: {
int width = Utils.dip2px(context, 300.0f);
int height = Utils.dip2px(context, 200.0f);
Glide.with(context)
.load(R.mipmap.check)
.apply(overrideOf(width, height))
.apply(bitmapTransform(new MultiTransformation<>(new CenterCrop(),
new MaskTransformation(R.mipmap.mask_chat_right))))
.into(holder.image);
break;
}
case CropTop:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(
new CropTransformation(Utils.dip2px(context, 300), Utils.dip2px(context, 100),
CropType.TOP)))
.into(holder.image);
break;
case CropCenter:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(
new CropTransformation(Utils.dip2px(context, 300), Utils.dip2px(context, 100), CropType.CENTER)))
.into(holder.image);
break;
case CropBottom:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(
new CropTransformation(Utils.dip2px(context, 300), Utils.dip2px(context, 100),
CropType.BOTTOM)))
.into(holder.image);
break;
case CropSquare:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new CropSquareTransformation()))
.into(holder.image);
break;
case CropCircle:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new CropCircleTransformation()))
.into(holder.image);
break;
case ColorFilter:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new ColorFilterTransformation(Color.argb(80, 255, 0, 0))))
.into(holder.image);
break;
case Grayscale:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new GrayscaleTransformation()))
.into(holder.image);
break;
case RoundedCorners:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new RoundedCornersTransformation(45, 0,
RoundedCornersTransformation.CornerType.BOTTOM)))
.into(holder.image);
break;
case Blur:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new BlurTransformation(250)))
.into(holder.image);
break;
case SupportRSBlur:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new SupportRSBlurTransformation(25, 10)))
.into(holder.image);
break;
case Toon:
Glide.with(context)
.load(R.mipmap.demo)
.apply(bitmapTransform(new ToonFilterTransformation()))
.into(holder.image);
break;
case Sepia:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new SepiaFilterTransformation()))
.into(holder.image);
break;
case Contrast:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new ContrastFilterTransformation(2.0f)))
.into(holder.image);
break;
case Invert:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new InvertFilterTransformation()))
.into(holder.image);
break;
case Pixel:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new PixelationFilterTransformation(20)))
.into(holder.image);
break;
case Sketch:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new SketchFilterTransformation()))
.into(holder.image);
break;
case Swirl:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(
new SwirlFilterTransformation(0.5f, 1.0f, new PointF(0.5f, 0.5f))).dontAnimate())
.into(holder.image);
break;
case Brightness:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new BrightnessFilterTransformation(0.5f)).dontAnimate())
.into(holder.image);
break;
case Kuawahara:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new KuwaharaFilterTransformation(25)).dontAnimate())
.into(holder.image);
break;
case Vignette:
Glide.with(context)
.load(R.mipmap.check)
.apply(bitmapTransform(new VignetteFilterTransformation(new PointF(0.5f, 0.5f),
new float[] { 0.0f, 0.0f, 0.0f }, 0f, 0.75f)).dontAnimate())
.into(holder.image);
break;
}
holder.title.setText(dataSet.get(position).name());
}
要分析这个函数,其实很简单
首先看开头
可以看到,这个函数的两个参数分别是ViewHolder的对象和position值
不难猜到,这个函数的作用就是把一个ViewHolder和一个position一一对应起来
那么我们想一下,如果要我们自己写,那么应该怎么写呢
当然是首先拿到position,然后把这个position和对应的viewholder联系起来即可,实际上我们也是这么做的
MASK
对位掩模操作(MASK),你的底层图片(简称底片)大小肯定是确定的,这个我们是不能进行更改的(确切的说,应该是不会去更改,想改还是可以得),因为你的底片大小定义在这里
显然,你的底片大小是:宽250dp 高250dp
那么你的掩模板大小的宽和高都应该接近于250dp,这样掩模的效果是最好的
比如说,我们把掩模板宽设为266dp,高设为252dp
这样做是什么意思呢?就是说,你的掩模板里的东西是多少像素
如果说你按照上面的设置,显示出来的效果是这样的:
如果你把数字改小一些,比如宽慰2dp,高为2dp,那么效果就是这样的:
想明白了这个,接下来就很简单了
Blur
Blur的操作,同样很简单
大部分的参数含义都是和上面一样的,因为少了掩模板的操作,因此Blur的操作其实更加简单
这里需要注意一下的是,radius参数的大小可以决定你的模糊程度,这个数值越大,就越模糊