Glide 占位符、選項、變換

Glide 占位符

Glide 選項

Glide 變換

一、占位符

1.1 類型

Glide 允許用戶指定三種不同類型的占位符,分別在三種不同場景使用:

  • placeholder

  • error

  • fallback

1.1.1 占位符 (Placeholder)

占位符是當請求正在執(zhí)行時被展示的 Drawable。當請求成功完成時,占位符會被請求到的資源替換。如果被請求的資源是從內(nèi)存中加載出來的,那么占位符可能根本不會被顯示。如果請求失敗并且沒有設(shè)置 error Drawable,則占位符將被持續(xù)展示。類似地,如果請求的 url/modelnull,并且 error Drawablefallback 都沒有設(shè)置,那么占位符也會繼續(xù)顯示。

使用 generated API :

GlideApp.with(fragment)
  .load(url)
  .placeholder(R.drawable.placeholder)
  .into(view);

或者:

GlideApp.with(fragment)
  .load(url)
  .placeholder(new ColorDrawable(Color.BLACK))
  .into(view);

1.1.2 錯誤符 (Error)

error Drawable 在請求永久性失敗時展示。error Drawable 同樣也在請求的 url/modelnull,且并沒有設(shè)置 fallback Drawable 時展示。

使用 generated API :

GlideApp.with(fragment)
  .load(url)
  .error(R.drawable.error)
  .into(view);

或者:

GlideApp.with(fragment)
  .load(url)
  .error(new ColorDrawable(Color.RED))
  .into(view);

1.1.3 后備回調(diào)符 (Fallback)

fallback Drawable 在請求的 url/modelnull 時展示。設(shè)計 fallback Drawable 的主要目的是允許用戶指示 null 是否為可接受的正常情況。例如,一個 null 的個人資料 url 可能暗示這個用戶沒有設(shè)置頭像,因此應該使用默認頭像。然而,null 也可能表明這個元數(shù)據(jù)根本就是不合法的,或者取不到。 默認情況下Glide 將 null 作為錯誤處理,所以可以接受 null 的應用應當顯式地設(shè)置一個 fallback Drawable。

使用 generated API:

GlideApp.with(fragment)
  .load(url)
  .fallback(R.drawable.fallback)
  .into(view);

或者:

GlideApp.with(fragment)
  .load(url)
  .fallback(new ColorDrawable(Color.GREY))
  .into(view);

1.2 FAQ

1.2.1 占位符是異步加載的嗎?

No。占位符是在主線程從 Android Resources 加載的。我們通常希望占位符比較小且容易被系統(tǒng)資源緩存機制緩存起來。

1.2.2 變換是否會被應用到占位符上?

No。Transformation 僅被應用于被請求的資源,而不會對任何占位符使用。

在應用中包含必須在運行時做變換才能使用的圖片資源是很不劃算的。相反,在應用中包含一個確切符合尺寸和形狀要求的資源版本幾乎總是一個更好的辦法。假如你正在加載圓形圖片,你可能希望在你的應用中包含圓形的占位符。另外你也可以考慮自定義一個 View 來剪裁 (clip) 你的占位符,而達到你想要的變換效果。

1.2.3 在多個不同的 View 上使用相同的 Drawable 可行么?

通??梢?,但不是絕對的。任何無狀態(tài) (non-stateful) 的 Drawable(例如 BitmapDrawable)通常都是 ok 的。但是有狀態(tài)的 Drawable 不一樣,在同一時間多個 View 上展示它們通常不是很安全,因為多個 View 會立刻修改 (mutate) Drawable 。對于有狀態(tài)的 Drawable ,建議傳入一個資源 ID,或者使用 newDrawable() 來給每個請求傳入一個新的拷貝。

二、選項

2.1 請求選項

Glide 中的大部分設(shè)置項都可以通過 RequestOptions 類和 apply() 方法來應用到程序中。

使用 request options 可以實現(xiàn)(包括但不限于):

  • 占位符 (Placeholders)

  • 轉(zhuǎn)換 (Transformations)

  • 緩存策略 (Caching Strategies)

  • 組件特有的設(shè)置項,例如編碼質(zhì)量,或 Bitmap 的解碼配置等。

例如,要應用一個 CenterCrop 轉(zhuǎn)換,你可以使用以下代碼:

import static com.bumptech.glide.request.RequestOptions.centerCropTransform;

Glide.with(fragment)
    .load(url)
    .apply(centerCropTransform(context))
    .into(imageView);

在這個例子中使用了對 RequestOptions 類里的方法的靜態(tài) import,這會讓代碼看起來更簡潔流暢。

如果你想讓你的應用的不同部分之間共享相同的加載選項,你也可以初始化一個新的 RequestOptions 對象,并在每次加載時傳入這個對象:

RequestOptions cropOptions = new RequestOptions().centerCrop(context);
...
Glide.with(fragment)
    .load(url)
    .apply(cropOptions)
    .into(imageView);

apply() 方法可以被調(diào)用多次,因此 RequestOption 可以被組合使用。如果 RequestOptions 對象之間存在相互沖突的設(shè)置,那么只有最后一個被應用的 RequestOptions 會生效。

2.2 Generated API

如果你正在使用 Generated API, 所有的請求選項方法都會被內(nèi)聯(lián)并可以直接使用:

GlideApp.with(fragment)
    .load(url)
    .centerCrop()
    .into(imageView);

2.3 過渡選項

TransitionOptions 用于決定你的加載完成時會發(fā)生什么。

使用 TransitionOption 可以應用以下變換:

  • View 淡入

  • 與占位符交叉淡入

  • 或者什么都不發(fā)生

如果不使用變換,你的圖像將會“跳入”其顯示位置,直接替換掉之前的圖像。為了避免這種突然的改變,你可以淡入 view,或者讓多個 Drawable 交叉淡入,而這些都需要使用 TransitionOptions 完成。

例如,要應用一個交叉淡入變換:

import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;

Glide.with(fragment)
    .load(url)
    .transition(withCrossFade())
    .into(view);

不同于 RequestOptions,TransitionOptions 是特定資源類型獨有的,你能使用的變換取決于你讓 Glide 加載哪種類型的資源。

這樣的結(jié)果是,假如你請求加載一個 Bitmap ,你需要使用 BitmapTransitionOptions,而不是 DrawableTransitionOptions 。同樣,當你請求加載 Bitmap 時,你只需要做簡單的淡入,而不需要做復雜的交叉淡入。

2.4 RequestBuilder

RequestBuilder 是 Glide 中請求的骨架,負責攜帶請求的 url 和你的設(shè)置項來開始一個新的加載過程。

使用 RequestBuilder 可以指定:

  • 你想加載的資源類型 (Bitmap,Drawable,或其他)

  • 你要加載的資源地址 (url/model)

  • 你想最終加載到的 View

  • 任何你想應用的(一個或多個)RequestOption 對象

  • 任何你想應用的(一個或多個)TransitionOption 對象

  • 任何你想加載的縮略圖 thumbnail()

要構(gòu)造一個 RequestBuilder 對象,你可以通過先調(diào)用 Glide.with() 然后再調(diào)用某一個 as 方法來完成:

RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).asDrawable();

或先調(diào)用 Glide.with() 然后 load()

RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).load(url);

2.4.1 選擇資源類型

RequestBuilders 是特定于它們將要加載的資源類型的。默認情況下你會得到一個 Drawable RequestBuilder,但你可以使用 as... 系列方法來改變請求類型。例如,如果你調(diào)用了 asBitmap(),你就將獲得一個 BitmapRequestBuilder 對象,而不是默認的 Drawable RequestBuilder。

RequestBuilder<Bitmap> requestBuilder = Glide.with(fragment).asBitmap();

2.4.2 應用 RequestOptions

前面提到,可以使用 apply() 方法應用 RequestOptions,使用 transition() 方法應用 TransitionOptions。

RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).asDrawable();
requestBuilder.apply(requestOptions);
requestBuilder.transition(transitionOptions);

RequestBuilder 也可以被復用于開始多個請求:

RequestBuilder<Drawable> requestBuilder =
        Glide.with(fragment)
            .asDrawable()
            .apply(requestOptions);

for (int i = 0; i < numViews; i++) {
   ImageView view = viewGroup.getChildAt(i);
   String url = urls.get(i);
   requestBuilder.load(url).into(view);

2.4.3 縮略圖 (Thumbnail) 請求

Glide 的 thumbnail() API 允許你指定一個 RequestBuilder 以與你的主請求并行啟動。thumbnail() 會在主請求加載過程中展示。如果主請求在縮略圖請求之前完成,則縮略圖請求中的圖像將不會被展示。thumbnail() API 允許你簡單快速地加載圖像的低分辨率版本,并且同時加載圖像的無損版本,這可以減少用戶盯著加載指示器,例如進度條的時間。

thumbnail() API 對本地和遠程圖片都適用,尤其是當?shù)头直媛士s略圖存在于 Glide 的磁盤緩存時,它們將很快被加載出來。

thumbnail() API 使用起來相對簡單:

Glide.with(fragment)
  .load(url)
  .thumbnail(Glide.with(fragment)
    .load(thumbnailUrl))
  .into(imageView);

只要你的 thumbnailUrl 指向的圖片比你的主 url 的分辨率更低,它將會很好地工作。相當數(shù)量的加載 API 提供了不同的指定圖片尺寸的方法,它們尤其適用于 thumbnail() API。

如果你僅僅想加載一個本地圖像,或者你只有一個單獨的遠程 URL, 你仍然可以從縮略圖 API 受益。請使用 Glide 的 overridesizeMultiplier API 來強制 Glide 在縮略圖請求中加載一個低分辨率圖像:

int thumbnailSize = ...;
Glide.with(fragment)
  .load(localUri)
  .thumbnail(Glide.with(fragment)
    .load(localUri)
    .override(thumbnailSize))
  .into(view);

thumbnail() 方法有一個簡化版本,它只需要一個 sizeMultiplier 參數(shù)。如果你只是想為你的加載相同的圖片,但尺寸為 ViewTarget 的某個百分比的話特別有用:

Glide.with(fragment)
  .load(localUri)
  .thumbnail(/*sizeMultiplier=*/ 0.25f)
  .into(imageView);

2.4.4 在失敗時開始新的請求

從 Glide 4.3.0 開始,你現(xiàn)在可以使用 error API 來指定一個 RequestBuilder,以在主請求失敗時開始一次新的加載。例如,在請求 primaryUrl 失敗后加載 fallbackUrl

Glide.with(fragment)
  .load(primaryUrl)
  .error(Glide.with(fragment)
      .load(fallbackUrl))
  .into(imageView);

如果主請求成功完成,這個 error RequestBuilder 將不會被啟動。如果你同時指定了一個 thumbnail() 和一個 error() RequestBuilder,則這個后備的 RequestBuilder 將在主請求失敗時啟動,即使縮略圖請求成功也是如此。

2.5 組件選項

Option 類是給 Glide 的組件添加參數(shù)的通用辦法,包括 ModelLoaders,ResourceDecodersResourceEncoders,Encoders 等等。一些 Glide 的內(nèi)置組件提供了設(shè)置項,自定義的組件也可以添加設(shè)置項。

Option 通過 RequestOptions 類應用到請求上:

import static com.bumptech.glide.request.RequestOptions.option;

Glide.with(context)
  .load(url)
  .apply(option(MyCustomModelLoader.TIMEOUT_MS, 1000L))
  .into(imageView);

你也可以創(chuàng)建一個全新的 RequestOptions 對象:

RequestOptions options = new RequestOptions()
  .set(MyCustomModelLoader.TIMEOUT_MS, 1000L);

Glide.with(context)
  .load(url)
  .apply(options)
  .into(imageView);

或者使用 Generated API

GlideApp.with(context)
  .load(url)
  .set(MyCustomModelLoader.TIMEOUT_MS, 1000L)
  .into(imageView);

三、變換

3.1 關(guān)于變換

在 Glide 中,Transformations 可以獲取資源并修改它,然后返回被修改后的資源。通常變換操作是用來完成剪裁或?qū)ξ粓D應用過濾器,但它也可以用于轉(zhuǎn)換 GIF 動畫,甚至自定義的資源類型。

3.2 內(nèi)置類型

Glide 提供了很多內(nèi)置的變換,包括:

  • CenterCrop

  • FitCenter

  • CircleCrop

3.3 應用

通過 RequestOptions 類可以應用變換:

3.3.1 默認變換

RequestOptions options = new RequestOptions();
options.centerCrop();

Glide.with(fragment)
    .load(url)
    .apply(options)
    .into(imageView);

大多數(shù)內(nèi)置的變換都有靜態(tài)的 import ,這是為 API 的流暢性考慮的。例如,你可以通過靜態(tài)方法應用一個 FitCenter 變換:

import static com.bumptech.glide.request.RequestOptions.fitCenterTransform;

Glide.with(fragment)
    .load(url)
    .apply(fitCenterTransform())
    .into(imageView);

如果你正在使用 Generated API,那么這些變換方法已經(jīng)被內(nèi)聯(lián)了,所以使用起來甚至更為輕松:

GlideApp.with(fragment)
  .load(url)
  .fitCenter()
  .into(imageView);

3.3.2 多重變換

默認情況下,每個 transform() 調(diào)用,或任何特定轉(zhuǎn)換方法 (fitCenter()centerCrop(),bitmapTransform() 等) 的調(diào)用都會替換掉之前的變換。

如果你想在單次加載中應用多個變換,請使用 MultiTransformation 類。

使用 generated API:

Glide.with(fragment)
  .load(url)
  .transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation())
  .into(imageView);

或結(jié)合使用快捷方法和 generated API:

GlideApp.with(fragment)
  .load(url)
  .transforms(new FitCenter(), new YourCustomTransformation())
  .into(imageView);

請注意,你向 MultiTransformation 的構(gòu)造器傳入變換參數(shù)的順序,決定了這些變換的應用順序。

3.4 定制變換

盡管 Glide 提供了各種各樣的內(nèi)置 Transformation 實現(xiàn),如果你需要額外的功能,你也可以實現(xiàn)你自己的 Transformation。

3.4.1 BitmapTransformation

如果你只需要變換 Bitmap,最好是從繼承 BitmapTransformation 開始。BitmapTransformation 為我們處理了一些基礎(chǔ)的東西,例如,如果你的變換返回了一個新修改的 Bitmap,BitmapTransformation 將負責提取和回收原始的 Bitmap。

一個簡單的實現(xiàn)看起來可能像這樣:

public class FillSpace extends BitmapTransformation {
    private static final String ID = "com.bumptech.glide.transformations.FillSpace";
    private static final String ID_BYTES = ID.getBytes(STRING_CHARSET_NAME);

    @Override
    public Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        if (toTransform.getWidth() == outWidth && toTransform.getHeight() == outHeight) {
            return toTransform;
        }

        return Bitmap.createScaledBitmap(toTransform, outWidth, outHeight, /*filter=*/ true);
    }

    @Override
    public void equals(Object o) {
      return o instanceof FillSpace;
    }

    @Override
    public int hashCode() {
      return ID.hashCode();
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest)
        throws UnsupportedEncodingException {
      messageDigest.update(ID_BYTES);
    }
}

盡管你的 Transformation 會比這個示例更復雜,但它應該包含了相同的基本元素和復寫方法。

3.4.2 必需的方法

請?zhí)貏e注意,對于任何 Transformation 子類,包括 BitmapTransformation,你都有三個方法必須實現(xiàn),以使得磁盤和內(nèi)存緩存正確地工作:

  1. equals()

  2. hashCode()

  3. updateDiskCacheKey()

如果你的 Transformation 沒有參數(shù),通常使用一個包含完整包限定名的 static final String 來作為一個 ID,它可以構(gòu)成 hashCode() 的基礎(chǔ),并可用于更新 updateDiskCacheKey() 傳入的 MessageDigest。如果你的 Transformation 需要參數(shù)而且它會影響到 Bitmap 被變換的方式,它們也必須被包含到這三個方法中。

例如,Glide 的 RoundedCorners 變換接受一個 int,它決定了圓角的弧度。它的 equals(),hashCode()updateDiskCacheKey 實現(xiàn)看起來像這樣:

  @Override
  public boolean equals(Object o) {
    if (o instanceof RoundedCorners) {
      RoundedCorners other = (RoundedCorners) o;
      return roundingRadius == other.roundingRadius;
    }
    return false;
  }

  @Override
  public int hashCode() {
    return Util.hashCode(ID.hashCode(),
        Util.hashCode(roundingRadius));
  }

  @Override
  public void updateDiskCacheKey(MessageDigest messageDigest) {
    messageDigest.update(ID_BYTES);

    byte[] radiusData = ByteBuffer.allocate(4).putInt(roundingRadius).array();
    messageDigest.update(radiusData);
  }

原來的 String 仍然保留,但 roundingRadius 被包含到了三個方法中。這里,updateDiskCacheKey() 方法還演示了你可以如何使用 ByteBuffer 來包含基本參數(shù)到你的 updateDiskCacheKey() 實現(xiàn)中。

不要忘記 equals() / hashCode()!

值得重申的一點是,為了讓內(nèi)存緩存正常地工作你是否必須實現(xiàn) equals()hashCode() 方法。很不幸,即使你沒有復寫這兩個方法,BitmapTransformationTransformation 也能通過編譯,但這并不意味著它們能正常工作。

3.5 Glide中的特殊行為

3.5.1 重用變換

Transformation 的設(shè)計初衷是無狀態(tài)的。因此,在多個加載中復用 Transformation 應當總是安全的。創(chuàng)建一次 Transformation 并在多個加載中使用它,通常是很好的實踐。

3.5.2 ImageView 的自動變換

在 Glide 中,當你為一個 ImageView 開始加載時,Glide 可能會自動應用 FitCenterCenterCrop,這取決于 view 的 ScaleType。如果 scaleTypeCENTER_CROP,Glide 將會自動應用 CenterCrop 變換。如果 scaleTypeFIT_CENTERCENTER_INSIDE,Glide 會自動使用 FitCenter 變換。

當然,你總有權(quán)利覆寫默認的變換,只需要一個帶有 Transformation 集合的 RequestOptions 即可。另外,你也可以通過使用 dontTransform() 確保不會自動應用任何變換。

3.5.3 自定義資源

因為 Glide 4.0 允許你指定你將解碼的資源的父類型,你可能無法確切地知道將會應用何種變換。例如,當你使用 asDrawable() (或就是普通的 with(),因為 asDrawable() 是默認情形) 來加載 Drawable 資源時,你可能會得到 BitmapDrawable 子類,也有可能得到 GifDrawable 子類。

為了確保你添加到 RequestOptions 中的任何變換都會被使用,Glide將 Transformation 添加到一個 Map 中保存,其 Key 為你提供變換的資源類型。當資源被成功解碼時,Glide 使用這個 Map 來取回對應的 Transformation

Glide 可以將 Bitmap Transformation 應用到 BitmapDrawable, GifDrawable,以及 Bitmap 資源上,因此通常你只需要編寫和應用 Bitmap Transformation。然而,如果你添加了額外的資源類型,你可能需要考慮派生 RequestOptions 類,并且,在內(nèi)置的這些 Bitmap Transformations 之外,你還需要為你的自定義資源類型提供一個 Transformation。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容