提交 da4ce795 编写于 作者: S Sam Judd

Improve thumbnail performance.

上级 4a5c5613
...@@ -5,6 +5,7 @@ import android.widget.ImageView; ...@@ -5,6 +5,7 @@ import android.widget.ImageView;
import com.bumptech.glide.request.GlideAnimation; import com.bumptech.glide.request.GlideAnimation;
public class DrawableImageViewTarget extends ViewTarget<ImageView, Drawable> { public class DrawableImageViewTarget extends ViewTarget<ImageView, Drawable> {
private static final float SQUARE_RATIO_MARGIN = 0.05f;
private final ImageView view; private final ImageView view;
public DrawableImageViewTarget(ImageView view) { public DrawableImageViewTarget(ImageView view) {
...@@ -14,6 +15,19 @@ public class DrawableImageViewTarget extends ViewTarget<ImageView, Drawable> { ...@@ -14,6 +15,19 @@ public class DrawableImageViewTarget extends ViewTarget<ImageView, Drawable> {
@Override @Override
public void onResourceReady(Drawable resource, GlideAnimation<Drawable> animation) { public void onResourceReady(Drawable resource, GlideAnimation<Drawable> animation) {
//TODO: Try to generalize this to other sizes/shapes.
// This is a dirty hack that tries to make loading square thumbnails and then square full images less costly by
// forcing both the smaller thumb and the larger version to have exactly the same intrinsic dimensions. If a
// drawable is replaced in an ImageView by another drawable with different intrinsic dimensions, the ImageView
// requests a layout. Scrolling rapidly while replacing thumbs with larger images triggers lots of these calls
// and causes significant amounts of jank.
float viewRatio = view.getWidth() / (float) view.getHeight();
float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN && Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
resource = new SquaringDrawable(resource, view.getWidth());
}
if (animation == null || !animation.animate(view.getDrawable(), resource, view, this)) { if (animation == null || !animation.animate(view.getDrawable(), resource, view, this)) {
view.setImageDrawable(resource); view.setImageDrawable(resource);
} }
......
package com.bumptech.glide.request.target;
import android.annotation.TargetApi;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
/**
* A wrapper drawable to square the wrapped drawable so that it expands to fill a square with exactly the given side
* length. The goal of this drawable is to ensure that square thumbnail drawables always match the size of the view
* they will be displayed in to avoid a costly requestLayout call. This class should not be used with views or drawables
* that are not square.
*/
public class SquaringDrawable extends Drawable {
private final Drawable wrapped;
private int side;
public SquaringDrawable(Drawable wrapped, int side) {
this.wrapped = wrapped;
this.side = side;
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
wrapped.setBounds(left, top, right, bottom);
}
@Override
public void setBounds(Rect bounds) {
super.setBounds(bounds);
wrapped.setBounds(bounds);
}
public void setChangingConfigurations(int configs) {
wrapped.setChangingConfigurations(configs);
}
@Override
public int getChangingConfigurations() {
return wrapped.getChangingConfigurations();
}
@Override
public void setDither(boolean dither) {
wrapped.setDither(dither);
}
@Override
public void setFilterBitmap(boolean filter) {
wrapped.setFilterBitmap(filter);
}
@TargetApi(11)
@Override
public Callback getCallback() {
return wrapped.getCallback();
}
@TargetApi(19)
@Override
public int getAlpha() {
return wrapped.getAlpha();
}
@Override
public void setColorFilter(int color, PorterDuff.Mode mode) {
wrapped.setColorFilter(color, mode);
}
@Override
public void clearColorFilter() {
wrapped.clearColorFilter();
}
@Override
public Drawable getCurrent() {
return wrapped.getCurrent();
}
@Override
public boolean setVisible(boolean visible, boolean restart) {
return wrapped.setVisible(visible, restart);
}
@Override
public int getIntrinsicWidth() {
return side;
}
@Override
public int getIntrinsicHeight() {
return side;
}
@Override
public int getMinimumWidth() {
return wrapped.getMinimumWidth();
}
@Override
public int getMinimumHeight() {
return wrapped.getMinimumHeight();
}
@Override
public boolean getPadding(Rect padding) {
return wrapped.getPadding(padding);
}
@Override
public void invalidateSelf() {
super.invalidateSelf(); //To change body of overridden methods use File | Settings | File Templates.
wrapped.invalidateSelf();
}
@Override
public void unscheduleSelf(Runnable what) {
super.unscheduleSelf(what); //To change body of overridden methods use File | Settings | File Templates.
wrapped.unscheduleSelf(what);
}
@Override
public void scheduleSelf(Runnable what, long when) {
super.scheduleSelf(what, when); //To change body of overridden methods use File | Settings | File Templates.
wrapped.scheduleSelf(what, when);
}
@Override
public void draw(Canvas canvas) {
wrapped.draw(canvas);
}
@Override
public void setAlpha(int i) {
wrapped.setAlpha(i);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
wrapped.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return wrapped.getOpacity();
}
}
...@@ -7,7 +7,7 @@ import com.bumptech.glide.request.Request; ...@@ -7,7 +7,7 @@ import com.bumptech.glide.request.Request;
/** /**
* An interface that Glide can load an image into * An interface that Glide can load an image into
* *
* @param <Z> The type of resource the target can display. * @param <R> The type of resource the target can display.
*/ */
public interface Target<R> { public interface Target<R> {
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android" <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:scaleType="centerCrop"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent"/> android:layout_height="fill_parent"/>
...@@ -99,9 +99,8 @@ public class FlickrPhotoGrid extends SherlockFragment implements PhotoViewer { ...@@ -99,9 +99,8 @@ public class FlickrPhotoGrid extends SherlockFragment implements PhotoViewer {
protected GenericRequestBuilder getRequestBuilder(Photo item) { protected GenericRequestBuilder getRequestBuilder(Photo item) {
return Glide.with(FlickrPhotoGrid.this) return Glide.with(FlickrPhotoGrid.this)
.loadFromImage(item) .loadFromImage(item)
.override(Api.THUMB_SIZE, Api.THUMB_SIZE) .override(Api.SQUARE_THUMB_SIZE, Api.SQUARE_THUMB_SIZE)
.priority(Priority.HIGH) .priority(Priority.HIGH);
.centerCrop();
} }
} }
...@@ -150,8 +149,7 @@ public class FlickrPhotoGrid extends SherlockFragment implements PhotoViewer { ...@@ -150,8 +149,7 @@ public class FlickrPhotoGrid extends SherlockFragment implements PhotoViewer {
.loadFromImage(current) .loadFromImage(current)
.thumbnail(Glide.with(FlickrPhotoGrid.this) .thumbnail(Glide.with(FlickrPhotoGrid.this)
.loadFromImage(current) .loadFromImage(current)
.override(Api.THUMB_SIZE, Api.THUMB_SIZE) .override(Api.SQUARE_THUMB_SIZE, Api.SQUARE_THUMB_SIZE)
.centerCrop()
) )
.animate(R.anim.fade_in) .animate(R.anim.fade_in)
.centerCrop() .centerCrop()
......
...@@ -116,7 +116,8 @@ public class FlickrPhotoList extends SherlockFragment implements PhotoViewer { ...@@ -116,7 +116,8 @@ public class FlickrPhotoList extends SherlockFragment implements PhotoViewer {
.loadFromImage(item) .loadFromImage(item)
.thumbnail(Glide.with(FlickrPhotoList.this) .thumbnail(Glide.with(FlickrPhotoList.this)
.loadFromImage(item) .loadFromImage(item)
.override(Api.THUMB_SIZE, Api.THUMB_SIZE)) .override(Api.SQUARE_THUMB_SIZE, Api.SQUARE_THUMB_SIZE)
)
.centerCrop(); .centerCrop();
} }
} }
...@@ -176,7 +177,7 @@ public class FlickrPhotoList extends SherlockFragment implements PhotoViewer { ...@@ -176,7 +177,7 @@ public class FlickrPhotoList extends SherlockFragment implements PhotoViewer {
.placeholder(new ColorDrawable(Color.GRAY)) .placeholder(new ColorDrawable(Color.GRAY))
.thumbnail(Glide.with(FlickrPhotoList.this) .thumbnail(Glide.with(FlickrPhotoList.this)
.loadFromImage(current) .loadFromImage(current)
.override(Api.THUMB_SIZE, Api.THUMB_SIZE)) .override(Api.SQUARE_THUMB_SIZE, Api.SQUARE_THUMB_SIZE))
.centerCrop() .centerCrop()
.crossFade(R.anim.fade_in, 150) .crossFade(R.anim.fade_in, 150)
.into(viewHolder.imageView); .into(viewHolder.imageView);
......
...@@ -45,7 +45,7 @@ public class Api { ...@@ -45,7 +45,7 @@ public class Api {
Collections.sort(SORTED_SIZE_KEYS); Collections.sort(SORTED_SIZE_KEYS);
} }
public static final int THUMB_SIZE = SORTED_SIZE_KEYS.get(0); public static final int SQUARE_THUMB_SIZE = SORTED_SIZE_KEYS.get(0);
private static String getSizeKey(int width, int height) { private static String getSizeKey(int width, int height) {
final int largestEdge = Math.max(width, height); final int largestEdge = Math.max(width, height);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册