public static String[] eatFoodyImages = {
"http://i.imgur.com/rFLNqWI.jpg",
"http://i.imgur.com/C9pBVt7.jpg",
"http://i.imgur.com/rT5vXE1.jpg",
"http://i.imgur.com/aIy5R2k.jpg",
"http://i.imgur.com/MoJs9pT.jpg",
"http://i.imgur.com/S963yEM.jpg",
"http://i.imgur.com/rLR2cyc.jpg",
"http://i.imgur.com/SEPdUIx.jpg",
"http://i.imgur.com/aC9OjaM.jpg",
"http://i.imgur.com/76Jfv9b.jpg",
"http://i.imgur.com/fUX7EIB.jpg",
"http://i.imgur.com/syELajx.jpg",
"http://i.imgur.com/COzBnru.jpg",
"http://i.imgur.com/Z3QjilA.jpg",
public class UsageExampleAdapter extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_usage_example_adapter);
listView.setAdapter(
new ImageListAdapter(
UsageExampleAdapter.this,
eatFoodyImages
public class ImageListAdapter extends ArrayAdapter {
private Context context;
private LayoutInflater inflater;
private String[] imageUrls;
public ImageListAdapter(Context context, String[] imageUrls) {
super(context, R.layout.listview_item_image, imageUrls);
this.context = context;
this.imageUrls = imageUrls;
inflater = LayoutInflater.from(context);
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
convertView = inflater.inflate(R.layout.listview_item_image, parent, false);
GlideApp
.with(context)
.load(imageUrls[position])
.into((ImageView) convertView);
return convertView;
图片过度Transitions
无论你是否使用占位图,在UI
过程中改变ImageView
的图片都是一个很大的动作。有一个简单的方法可以使这种改变变的更平滑,更容易让人接受,那就是使用
crossfade
动画。
GlideApp
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
.transition(DrawableTransitionOptions.withCrossFade())// withCrossFade(int duration)方法可以传入时间,默认时间是300毫秒
.into(imageViewCombined);
自定义过度动画
上面提供了crossfade
动画,但是有些时候我们需要自定义更多的样式。
Glide
也是支持xml
中自定义的动画文件的。
GlideApp
.with(context)
.load(eatFoodyImages[0])
.transition(GenericTransitionOptions.with(R.anim.zoom_in))
.into(imageView1);
图片大小调整
理想情况下,你的服务器或者API
能够返回所需分辨率的图片,这是在网络带宽、内存消耗和图片质量下的完美方案。
跟Picasso
比起来,Glide
在内存上占用更优化。Glide
在缓存和内存里自动限制图片的大小去适配ImageView
的尺寸。Picasso
也有同样的能力,但需要调用fit()
方法。用Glide
时,如果图片不需要自动适配ImageView
,调用override(horizontalSize, verticalSize)
,它会在将图片显示在ImageView
之前调整图片的大小。
这个设置也有利于没有明确目标,但已知尺寸的视图上。例如,如果app
想要预先缓存在splash
屏幕上,还没法测量出ImageVIews
具体宽高。但是如果你已经知道图片应当为多大,使用override
可以提供一个指定的大小的图片。
GlideApp
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200) // resizes the image to these dimensions (in pixel). resize does not respect aspect ratio
.into(imageViewResize);
对于任何图像的任何处理,调整图像的大小可能会扭曲长宽比,丑化图片的显示。在大多数情况下,你希望防止这种事情发生。Glide
提供了变换去处理图片显示,通过设置centerCrop
和fitCenter
,可以得到两个不同的效果。CenterCrop()
会缩放图片让图片充满整个ImageView
的边框,然后裁掉超出的部分。ImageVIew
会被完全填充满,但是图片可能不能完全显示出。
fitCenter()
会缩放图片让两边都相等或小于ImageView
的所需求的边框。图片会被完整显示,可能不能完全填充整个ImageView
。
GlideApp
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200) // resizes the image to these dimensions (in pixel)
.centerCrop() // this cropping technique scales the image so that it fills the requested bounds and then crops the extra.
.into(imageViewResizeCenterCrop);
GlideApp
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200)
.fitCenter()
.into(imageViewResizeFitCenter);
更变图片转换
上面介绍了两种自带的图片转换方式fitCenter
和centerCrop
。 但有些时候我们需要自定义一些别的转换方式,自定义转换方式需要继承BitmapTransformation
类。
public class BlurTransformation extends BitmapTransformation {
public BlurTransformation(Context context) {
super( context );
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return null; // todo
@Override
public String getId() {
return null; // todo
接下来使用Renderscript
来实现图片的模糊处理。
public class BlurTransformation extends BitmapTransformation {
private RenderScript rs;
public BlurTransformation(Context context) {
super( context );
rs = RenderScript.create( context );
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
Bitmap blurredBitmap = toTransform.copy( Bitmap.Config.ARGB_8888, true );
// Allocate memory for Renderscript to work with
Allocation input = Allocation.createFromBitmap(
blurredBitmap,
Allocation.MipmapControl.MIPMAP_FULL,
Allocation.USAGE_SHARED
Allocation output = Allocation.createTyped(rs, input.getType());
// Load up an instance of the specific script that we want to use.
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setInput(input);
// Set the blur radius
script.setRadius(10);
// Start the ScriptIntrinisicBlur
script.forEach(output);
// Copy the output to the blurred bitmap
output.copyTo(blurredBitmap);
toTransform.recycle();
return blurredBitmap;
@Override
public String getId() {
// getId()方法为这个变换描述了一个独有的识别。Glide使用那个关键字作为缓存系统的一部分。防止出现异常问题,确保其唯一。
return "blur";
传递你的类的实例作为.transform()
的参数。不管是图片还是gif
都可以进行变换。
GlideApp
.with(context)
.load(eatFoodyImages[0])
.transform(new BlurTransformation(context))
.into(imageView2);
通常,Glide
的fluent interface
允许方法被连接在一起,然而变换并不是这样的。确保你只调用.transform()
一次,不然之前的设置将会被覆盖!然而,你可以通过传递多个转换对象当作参数到.transform()
中来进行多重变换:
GlideApp
.with(context)
.load(eatFoodyImages[0])
.transform(
new MultiTransformation(
new GrayscaleTransformation(context),
new BlurTransformation(context)))
.into(imageView3);
播放gif
动画
String gifUrl = "http://i.kinja-img.com/gawker-media/image/upload/s--B7tUiM5l--/gf2r69yorbdesguga10i.gif";
GlideApp
.with(context)
.load(gifUrl)
.into(imageViewGif);
gif
检查
Glide
接受Gif
和图片作为load()
的参数。上面代码中潜在的一个问题,如果提供的源不是Gif
,可能是一个普通的图片。即使是一个完好的图片(非Gif
),Glide
也会加载失败。.error()
回调方法会被调用,并加载错误占位图。这样引入了一个额外的方法.asGif()
强迫生成一个Gif
。
GlideApp
.with(context)
.asGif()
.load(gifUrl)
.error(R.drawable.full_cake)
.into(imageViewGifAsGif);
把Gif
当作Bitmap
播放
如果你的app
需要显示一组网络URL
,可能包括普通的图片或者Gif
。在一些情况下,你可能并不在意是否要播放完整的Gif
。如果你只是想要显示Gif
的第一帧,当URl
指向的的确是Gif
,你可以调用asBitmap()
将其作为常规图片显示。
GlideApp
.with(context)
.asBitmap()
.load(gifUrl)
.into(imageViewGifAsBitmap);
显示本地视频缩略图
String filePath = "/storage/emulated/0/Pictures/example_video.mp4";
GlideApp
.with(context)
.asBitmap()
.load(Uri.fromFile(new File(filePath)))
.into(imageViewGifAsBitmap);
GlideApp
.with(context)
.load(gifUrl)
.asGif()
.error(R.drawable.full_cake)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.into(imageViewGif);
默认情况下,我们不用去特意的操作缓存设置,因为Glide
默认会使用内存和硬盘缓存,但是如果在知道某一个图片会快速变化时,你可能会关闭缓存功能。
GlideApp
.with(context)
.load(eatFoodyImages[0])
.skipMemoryCache(true)
.into(imageView1);
上面调用了.skipMemoryCache(true)
方法来告诉Glide
禁用内存缓存功能。这就意味着Glide
不会将图片缓存到内存中,但是这只是影响内存缓存,Glide
仍然会将图片
缓存到硬盘中来避免下一次显示该图片时重复请求。
如上面所讲到的,即使你关闭了内存缓存,所请求的图片仍然会被保存在设备的磁盘存储上。如果你有一张不段变化的图片,但是都是用的同一个URL
,你可能需要禁止磁盘缓存了。
你可以用.diskCacheStrategy()
方法改变Glide
的行为。不同于.skipMemoryCache()
方法,它将需要从枚举型变量中选择一个,而不是一个简单的boolean
。如果你想要禁止请求的磁盘缓存,使用枚举型变量DiskCacheStrategy.NONE
作为参数。
GlideApp
.with(context)
.load(eatFoodyImages[1])
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageView2);
上面的这种方式只是会禁用硬盘缓存,Glide
还会使用内存缓存。如果想把内存缓存和硬盘缓存都禁用,需要把上面的两个方法都设置
GlideApp
.with(context)
.load(eatFoodyImages[1])
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(imageView2);
自定义磁盘缓存行为
如从上面提到的,Glide
为硬盘缓存提供了多种设置方式。Glide
的磁盘缓存是相当复杂的。例如,Picasso
只缓存全尺寸图片。Glide
,会缓存原始,全尺寸的图片和额外的小版本图片。例如,如果你请求一个1000x1000
像素的图片,你的ImageView
是500x500
像素,Glide
会保存两个版本的图片到缓存里。
DiskCacheStrategy.NONE
禁用硬盘缓存功能
DiskCacheStrategy.DATA
只缓存原始的全尺寸图. 例如上面例子中1000x1000
像素的图片
DiskCacheStrategy.RESOURCE
只缓存最终剪辑转换后降低分辨的图片。例如上面离职中500x500
像素的图片
DiskCacheStrategy.AUTOMATIC
基于资源只能选择缓存策略(默认的行为)
DiskCacheStrategy.ALL
缓存所有分辨率对应的类型的图片
图片请求优先级
Glide
支持使用.priority()
方法来设置图片请求的优先级。
Priority.LOW
Priority.NORMAL
Priority.HIGH
Priority.IMMEDIATE
private void loadImageWithHighPriority() {
GlideApp
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.priority(Priority.HIGH)
.into(imageViewHero);
private void loadImagesWithLowPriority() {
GlideApp
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[1])
.priority(Priority.LOW)
.into(imageViewLowPrioLeft);
GlideApp
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[2])
.priority(Priority.LOW)
.into(imageViewLowPrioRight);
缩略图不同于前面文章中提到的占位图。占位图应当是跟app
绑定在一起的资源。缩略图是一个动态的占位图,可以从网络加载。缩略图也会被先加载,直到实际图片请求加载完毕。如果因为某些原因,缩略图获得的时间晚于原始图片,它并不会替代原始图片,而是简单地被忽略掉。
Glide
提供了两种产生缩略图的方式。第一种,是通过在加载的时候指定一个小的分辨率,产生一个缩略图。这个方法在ListView
和详细视图的组合中非常有用。如果你已经在ListView
中用到了250x250
像素的图片,那么在在详细视图中会需要一个更大分辨率的图片。然而从用户的角度,我们已经看见了一个小版本的图片,为什么需要好几秒,同样的图片(高分辨率的)才能被再次加载出来呢?
在这种情况下,从显示250x250
像素版本的图片平滑过渡到详细视图里查看大图更有意义。Glide
里的.thumbnail()
方法让这个变为可能。这里.thumbnal()
的参数是一个浮点乘法运算。
String internetUrl = "http://i.imgur.com/DvpvklR.png";
GlideApp
.with(context)
.load(internetUrl)
.thumbnail(0.1f)
.into(imageView);
例如,如果你传递一个0.1f
作为参数,Glide
会加载原始图片大小的10%
的图片。如果原始图片有1000x1000
像素,缩略图的分辨率为100x100
像素。
为.thumbnail()
传入一个浮点类型的参数,非常简单有效,但并不是总是有意义。如果缩略图的生成也需要从网络加载同样全分辨率图片后才可以,那这样加载速度并不会比不用缩略图快。
因此Glide
提供了另一个方法去加载和显示缩略图。第二种方式需要传递一个新的Glide
请求作为参数。
String internetUrl = "http://i.imgur.com/DvpvklR.png";
// setup Glide request without the into() method
RequestBuilder<Drawable> thumbnailRequest = GlideApp
.with(context)
.load(internetUrl);
// pass the request as a a parameter to the thumbnail request
GlideApp
.with(context)
.load(UsageExampleGifAndVideos.gifUrl)
.thumbnail(thumbnailRequest)
.into(imageView);
区别在于第一个缩略图请求是完全独立于第二个原始请求的。缩略图可以来自不同资源或者图片URL,你可以在它上面应用不同的变换。
android.graphics.Matrix
提供了旋转的方法:
Bitmap toTransform = ... // your bitmap source
Matrix matrix = new Matrix();
matrix.postRotate(rotateRotationAngle);
Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);
但是如果要在Glide
中使用旋转方法,需要用BitmapTransformation()
进行包裹:
public class RotateTransformation extends BitmapTransformation {
private float rotateRotationAngle = 0f;
public RotateTransformation(Context context, float rotateRotationAngle) {
super( context );
this.rotateRotationAngle = rotateRotationAngle;
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
Matrix matrix = new Matrix();
matrix.postRotate(rotateRotationAngle);
return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);
@Override
public String getId() {
return "rotate" + rotateRotationAngle;
然后将上面的方法传递到.transform()
中: