Android Glide設定預設圖片、異常圖片為圓形圖片
阿新 • • 發佈:2018-12-29
Android Glide4 非同步圖片框架
前言:
在專案開發中,是需要經常用到圓形圖片的,設定預設圖片,設定資源圖片等等。
若是,異常圖片,預設圖片都需要美工妹子做成圓形圖片,無疑增加了美工妹子的工作量。本著當活雷鋒的思想,程式設計師能搞定的事情,絕不麻煩美工妹子。
要說圖片非同步載入框架,現今最流行的非Glide莫屬,連谷歌I/O App都在使用,可見它的強大之處。
根據原始碼走向找到,設定預設圖片,異常圖片的方法。
眾所周知,Glide的開啟載入是通過呼叫GlideApp.with().....into()或者preload()
.
1. 首先,進入RequestBuilder類#into():
/**
* Set the target the resource will be loaded into.
*
* @param target The target to load the resource into.
* @return The given target.
* @see RequestManager#clear(Target)
*/
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request previous = target.getRequest();
if (previous != null) {
requestManager.clear(target);
}
requestOptions.lock();
Request request = buildRequest(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
2. 接下,原始碼來走向到RequestManager類中track():
void track(Target<?> target, Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
3. 在接下來,原始碼走向到RequestTracker類中runRequest():
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
4. 最終走向到SingleRequest類中begin():
@Override
public void begin() {
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
可以從原始碼target.onLoadStarted(getPlaceholderDrawable())
發覺,最後是通過Target物件的onLoadStarted()方法來設定預設空白圖片的。
SingleRequest類中設定異常圖片的原始碼:
private void setErrorPlaceholder() {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = null;
if (model == null) {
error = getFallbackDrawable();
}
// Either the model isn't null, or there was no fallback drawable set.
if (error == null) {
error = getErrorDrawable();
}
// The model isn't null, no fallback drawable was set or no error drawable was set.
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(error);
}
可以從原始碼target.onLoadFailed(error)
可知,是通過Target物件的onLoadFailed()方法來設定異常圖片的。
長征路已經走完一半,已經找到了最後的原始碼走向。剩下來,只需要自定義一個Target子類。
Glide中已經存在一個ImageViewTarget類,檢視原始碼如下:
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
implements Transition.ViewAdapter {
@Nullable
private Animatable animatable;
public ImageViewTarget(ImageView view) {
super(view);
}
/**
* Returns the current {@link android.graphics.drawable.Drawable} being displayed in the view
* using {@link android.widget.ImageView#getDrawable()}.
*/
@Override
@Nullable
public Drawable getCurrentDrawable() {
return view.getDrawable();
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param drawable {@inheritDoc}
*/
@Override
public void setDrawable(Drawable drawable) {
view.setImageDrawable(drawable);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param placeholder {@inheritDoc}
*/
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param errorDrawable {@inheritDoc}
*/
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
setResourceInternal(null);
setDrawable(errorDrawable);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param placeholder {@inheritDoc}
*/
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
super.onLoadCleared(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
@Override
public void onResourceReady(Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
@Override
public void onStart() {
if (animatable != null) {
animatable.start();
}
}
@Override
public void onStop() {
if (animatable != null) {
animatable.stop();
}
}
private void setResourceInternal(@Nullable Z resource) {
maybeUpdateAnimatable(resource);
setResource(resource);
}
private void maybeUpdateAnimatable(@Nullable Z resource) {
if (resource instanceof Animatable) {
animatable = (Animatable) resource;
animatable.start();
} else {
animatable = null;
}
}
protected abstract void setResource(@Nullable Z resource);
}
從原始碼可知,無論是空白圖片,還是異常圖片都是最後走向到setDrawable(Drawable drawable)
。
原始碼尋找之路已經走完,馬上就可以實現自己需要的需求,繼續擼起。
定義一個預設,異常,資源圖片都為圓形的 ImageViewTarget子類。
分析:
- 定義ImageViewTarget子類:
- 重寫
setDrawable(Drawable drawable)
,異常,預設空白圖片設定為圓形。 - 實現抽象方法
setResource( Bitmap resource)
,正常載入的資源圖片設定為圓形
程式碼編寫如下:
/**
*
* 設定 預設圖片,異常圖片,指定路徑的圖片為圓角圖片
*/
public class CircleBitmapTarget extends ImageViewTarget<Bitmap> {
public CircleBitmapTarget(ImageView view) {
super(view);
}
/**
* 從指定路徑載入的Bitmap
* @param resource
*/
@Override
protected void setResource(@Nullable Bitmap resource) {
bindCircleBitmapToImageView(resource);
}
/**
*
* onLoadFailed()和onLoadStarted呼叫該方法,用於設定預設的圖片和異常圖片
* 設定預設圖片
* @param drawable
*/
@Override
public void setDrawable(Drawable drawable) {
if (drawable instanceof BitmapDrawable){
Bitmap bitmap1= ((BitmapDrawable) drawable).getBitmap();
bindCircleBitmapToImageView(bitmap1);
}else{
view.setImageDrawable(drawable);
}
}
/**
* 通過RoundedBitmapDrawable繪製圓形Bitmap,且載入ImageView.
* @param bitmap
*/
private void bindCircleBitmapToImageView(Bitmap bitmap){
RoundedBitmapDrawable bitmapDrawable= RoundedBitmapDrawableFactory.create(view.getContext().getResources(),bitmap);
bitmapDrawable.setCircular(true);
view.setImageDrawable(bitmapDrawable);
}
}
最後使用方式:
GlideRequest<Bitmap> glideRequest = GlideApp.with(context).asBitmap();
glideRequest.load(imageUrl).error(errorResourceId)//異常時候顯示的圖片
.placeholder(placeResourceId)//載入成功前顯示的圖片
.fallback(nullResourceId)//url為空的時候,顯示的圖片
.into(new CircleBitmapTarget(imageView));//在RequestBuilder<Bitmap> 中使用自定義的ImageViewTarget