第 2 章 DRAWEE 指南

2018-02-24 15:57 更新

在XML中使用Drawees

Drawees 具有極大的可定制性。

下面的例子給出了可以配置的各種選項(xiàng):

<com.facebook.drawee.view.SimpleDraweeView
    android:id="@+id/my_image_view"
    android:layout_width="20dp"
    android:layout_height="20dp"
    fresco:fadeDuration="300"
    fresco:actualImageScaleType="focusCrop"
    fresco:placeholderImage="@color/wait_color"
    fresco:placeholderImageScaleType="fitCenter"
    fresco:failureImage="@drawable/error"
    fresco:failureImageScaleType="centerInside"
    fresco:retryImage="@drawable/retrying"
    fresco:retryImageScaleType="centerCrop"
    fresco:progressBarImage="@drawable/progress_bar"
    fresco:progressBarImageScaleType="centerInside"
    fresco:progressBarAutoRotateInterval="1000"
    fresco:backgroundImage="@color/blue"
    fresco:overlayImage="@drawable/watermark"
    fresco:pressedStateOverlayImage="@color/red"
    fresco:roundAsCircle="false"
    fresco:roundedCornerRadius="1dp"
    fresco:roundTopLeft="true"
    fresco:roundTopRight="false"
    fresco:roundBottomLeft="false"
    fresco:roundBottomRight="true"
    fresco:roundWithOverlayColor="@color/corner_color"
    fresco:roundingBorderWidth="2dp"
    fresco:roundingBorderColor="@color/border_color"
  />
必須設(shè)置layout_width和layout_height

如果沒有在XML中聲明這兩個(gè)屬性,將無(wú)法正確加載圖像。

wrap_content

Drawees 不支持 wrap_content 屬性。

所下載的圖像可能和占位圖尺寸不一致,如果設(shè)置出錯(cuò)圖或者重試圖的話,這些圖的尺寸也可能和所下載的圖尺寸不一致。

如果大小不一致,圖像下載完之后,假設(shè)如果是wrap_content,View將會(huì)重新layout,改變大小和位置。這將會(huì)導(dǎo)致界面跳躍。

固定寬高比

只有希望顯示的固定寬高比時(shí),可以使用wrap_content

如果希望顯示的圖片保持一定寬高比例,如果 4:3,則在XML中:

<com.facebook.drawee.view.SimpleDraweeView
    android:id="@+id/my_image_view"
    android:layout_width="20dp"
    android:layout_height="wrap_content"
    <!-- other attributes -->

然后在代碼中指定顯示比例:

mSimpleDraweeView.setAspectRatio(1.33f);

在JAVA代碼中使用Drawees

設(shè)置或更改要顯示的圖片

mSimpleDraweeView.setImageURI(uri);

如果要更加復(fù)雜的配置,可使用ControllerBuilder;

自定義顯示圖

一般情況下,在XML設(shè)置顯示效果即可, 如果想更多定制化,可以這樣:

創(chuàng)建一個(gè) builder 然后設(shè)置給 DraweeView:

List<Drawable> backgroundsList;
List<Drawable> overlaysList;
GenericDraweeHierarchyBuilder builder =
    new GenericDraweeHierarchyBuilder(getResources());
GenericDraweeHierarchy hierarchy = builder
    .setFadeDuration(300)
    .setPlaceholderImage(new MyCustomDrawable())
    .setBackgrounds(backgroundList)
    .setOverlays(overlaysList)
    .build();
mSimpleDraweeView.setHierarchy(hierarchy);

對(duì)于同一個(gè)View,請(qǐng)不要多次調(diào)用setHierarchy,即使這個(gè)View是可回收的。創(chuàng)建 DraweeHierarchy 的較為耗時(shí)的一個(gè)過(guò)程,應(yīng)該多次利用。

如果要改變所要顯示的圖片可使用setController 或者 setImageURI。

修改 DraweeHierarchy

DraweeHierarchy 的一些屬性可以在運(yùn)行時(shí)改變。

要改變這些屬性,首先獲取一個(gè)引用:

GenericDraweeHierarchy hierarchy = mSimpleDraweeView.getHierarchy();
修改占位圖

修改占位圖為資源id:

hierarchy.setPlaceholderImage(R.drawable.placeholderId);

或者修改為一個(gè) Drawable:

Drawable drawable; 
// 創(chuàng)建一個(gè)drawable
hierarchy.setPlaceholderImage(drawable);
修改顯示的圖像

修改縮放類型:

hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_INSIDE);

當(dāng)然,如果修改為 focusCrop, 需要指定一個(gè)居中點(diǎn):

hierarchy.setActualImageFocusPoint(point);

或者設(shè)置一個(gè)color filter:

ColorFilter filter;
// 創(chuàng)建filter
hierarchy.setActualImageColorFilter(filter);
圓角

All of the rounding related params, except the rounding method, can be modified. You get a RoundingParams object from the hierarchy, modify it, and set it back again:

除了圓角顯示方式(原來(lái)為圓角的不能修改為圓圈,反之亦然),其他圓角相關(guān)的呈現(xiàn)參數(shù), 具體參見這里 是可以動(dòng)態(tài)修改的。

如下: 獲取DraweeHierarchy的圓角顯示參數(shù),修改圓角半徑為10。

RoundingParams roundingParams = hierarchy.getRoundingParams();
roundingParams.setCornersRadius(10);
hierarchy.setRoundingParams(roundingParams);

Drawee的各種效果配置

內(nèi)容導(dǎo)航

定義

本頁(yè)說(shuō)明如何設(shè)置實(shí)現(xiàn)不同的圖片呈現(xiàn)效果。

除了要加載的圖片,其他各個(gè)設(shè)置都可以在xml中指定。在xml中指定的時(shí)候,可以是 drawable/下的資源,也可以顏色。

在Java 代碼中也可以指定。如果需要 通過(guò)程序設(shè)定 的話會(huì)接觸到這個(gè)類: GenericDraweeHierarchyBuilder

通過(guò)代碼設(shè)置是,設(shè)置的值可以是資源id,也可以是 Drawable 的子類。

創(chuàng)建完 GenericDraweeHierarchy 之后,也可以通過(guò)該類的相關(guān)方法,重新設(shè)置一些效果。

大多數(shù)的用戶呈現(xiàn)不同效果的drawables都是可以縮放的.

設(shè)置要加載的圖

除了需要加載的圖片是真正必須的,其他的都是可選的。如前所述,圖片可以來(lái)自多個(gè)地方。

所需加載的圖片實(shí)際是DraweeController的一個(gè)屬性,而不是 DraweeHierarchy 的屬性。

可使用setImageURI方法或者通過(guò)設(shè)置 DraweeController 來(lái)進(jìn)行設(shè)置。

對(duì)于要加載的圖片,除了可以設(shè)置縮放類型外,DraweeHierarchy 還公開出一些其他方法用來(lái)控制顯示效果:

  • focus point (居中焦點(diǎn), 用于 focusCrop 縮放模式)
  • color filter

默認(rèn)的縮放類型是: centerCrop

占位圖(Placeholder)

在調(diào)用setController 或者 setImageURI 之后,占位圖開始顯示,直到圖片加載完成。

對(duì)于漸進(jìn)式格式的JPEG圖片,占位圖會(huì)顯示直到滿足已加載的圖片解析度到達(dá)設(shè)定值。

XML 中屬性值: placeholderImage
Hierarchy builder中的方法: setPlaceholderImage
Hierarchy method: setPlaceholderImage
默認(rèn)值: a transparent ColorDrawable
默認(rèn)縮放類型: centerInside

設(shè)置加載失敗占位圖

如果URI是無(wú)效的,或者下載過(guò)程中網(wǎng)絡(luò)不可用,將會(huì)導(dǎo)致加載失敗。當(dāng)加載圖片出錯(cuò)時(shí),你可以設(shè)置一個(gè)出錯(cuò)提示圖片。

XML 中屬性值: failureImage
Hierarchy builder中的方法: setFailureImage
默認(rèn)值: The placeholder image
默認(rèn)縮放類型: centerInside

點(diǎn)擊重新加載圖

在加載失敗時(shí),可以設(shè)置點(diǎn)擊重新加載。這時(shí)提供一個(gè)圖片,加載失敗時(shí),會(huì)顯示這個(gè)圖片(而不是失敗提示圖片),提示用戶點(diǎn)擊重試。

ControllerBuilder 中如下設(shè)置:

.setTapToRetryEnabled(true)

加載失敗時(shí),image pipeline 會(huì)重試四次;如果還是加載失敗,則顯示加載失敗提示圖片。

XML 中屬性值: retryImage
Hierarchy builder中的方法: setRetryImage
默認(rèn)值: The placeholder image
默認(rèn)縮放類型: centerInside

顯示一個(gè)進(jìn)度條

設(shè)置一個(gè)進(jìn)度條圖片,提示用戶正在加載。目前,進(jìn)度條僅僅是提示正在loading,和加載進(jìn)度無(wú)關(guān)。

XML 中屬性值: progressBarImage
Hierarchy builder中的方法: setProgressBarImage
默認(rèn)值: None
默認(rèn)縮放類型: centerInside

背景

背景圖會(huì)最先繪制,在XML中只可以指定一個(gè)背景圖,但是在JAVA代碼中,可以指定多個(gè)背景圖。

當(dāng)指定一個(gè)背景圖列表的時(shí)候,列表中的第一項(xiàng)會(huì)被首先繪制,繪制在最下層,然后依次往上繪制。

背景圖片不支持縮放類型,會(huì)被強(qiáng)制到Drawee尺寸大小。

XML 中屬性值: backgroundImage
Hierarchy builder中的方法: setBackground,``setBackgrounds
默認(rèn)值: None
默認(rèn)縮放類型: N/A

設(shè)置疊加圖(Overlay)

疊加圖會(huì)最后被繪制。

和背景圖一樣,XML中只可以指定一個(gè),如果想指定多個(gè),可以通過(guò)JAVA代碼實(shí)現(xiàn)。

當(dāng)指定的疊加圖是一個(gè)列表的時(shí)候,列表第一個(gè)元素會(huì)被先繪制,最后一個(gè)元素最后被繪制到最上層。

同樣的,不支持各種縮放類型。

XML 中屬性值: overlayImage
Hierarchy builder中的方法: setOverlay,``setOverlays
默認(rèn)值: None
默認(rèn)縮放類型: N/A

設(shè)置按壓狀態(tài)下的疊加圖

同樣不支持縮放,用戶按壓DraweeView時(shí)呈現(xiàn)。

XML 中屬性值: pressedStateOverlayImage
Hierarchy builder中的方法: setPressedStateOverlay
默認(rèn)值: None
默認(rèn)縮放類型: N/A

縮放

對(duì)于 Drawee 的各種效果配置,其中一些是支持縮放類型的。

可用的縮放類型

類型 描述
center 居中,無(wú)縮放
centerCrop 保持寬高比縮小或放大,使得兩邊都大于或等于顯示邊界。居中顯示。
focusCrop 同centerCrop, 但居中點(diǎn)不是中點(diǎn),而是指定的某個(gè)點(diǎn)
centerInside 使兩邊都在顯示邊界內(nèi),居中顯示。
如果圖尺寸大于顯示邊界,則保持長(zhǎng)寬比縮小圖片。
fitCenter 保持寬高比,縮小或者放大,使得圖片完全顯示在顯示邊界內(nèi)。居中顯示
fitStart 同上。但不居中,和顯示邊界左上對(duì)齊
fitEnd 同fitCenter, 但不居中,和顯示邊界右下對(duì)齊
fitXY 不保存寬高比,填充滿顯示邊界
none 如要使用tile mode顯示, 需要設(shè)置為none

這些縮放類型和Android ImageView 支持的縮放類型幾乎一樣.

唯一不支持的縮放類型是matrix. Fresco 提供了focusCrop 作為補(bǔ)充。通常這個(gè)縮放效果更佳。

focusCrop

centerCrop縮放模式會(huì)保持長(zhǎng)寬比,縮放圖片,填充滿顯示邊界,居中顯示。這個(gè)縮放模式在通常情況下很有用。

但是對(duì)于人臉等圖片時(shí),一味地居中顯示,這個(gè)模式可能會(huì)裁剪掉一些有用的信息。

以人臉圖片為例,借助一些類庫(kù),我們可以識(shí)別出人臉?biāo)谖恢?。如果可以設(shè)置以人臉位置居中裁剪顯示,那么效果會(huì)好很多。

Fresco的focusCrop縮放模式正是為此而設(shè)計(jì)。只要提供一個(gè)居中聚焦點(diǎn),顯示時(shí)就會(huì)盡量以此點(diǎn)為中心。

居中點(diǎn)是以相對(duì)方式給出的,比如(0.5f, 0.5f)就是居中顯示,(0f, 0f)就是左上對(duì)齊顯示。

如果要使用此縮放模式,首先指定縮放模式。在XML:

  fresco:actualImageScaleType="focusCrop"

在Java代碼中

PointF focusPoint;
// your app populates the focus point
mSimpleDraweeView
    .getHierarchy()
    .setActualImageFocusPoint(focusPoint);

none

如果你要使用tile mode進(jìn)行顯示,那么需要將scale type 設(shè)置為none.

圓角和圓圈

Drawee 輕松支持圓角顯示,并且顯示圓角時(shí),并不復(fù)制和修改Bitmap對(duì)象,那樣太耗費(fèi)內(nèi)存。

圓角

圓角實(shí)際有2中呈現(xiàn)方式:

  1. 圓圈 - 設(shè)置roundAsCircle為true
  2. 圓角 - 設(shè)置roundedCornerRadius

設(shè)置圓角時(shí),支持4個(gè)角不同的半徑。XML中無(wú)法配置,但可在Java代碼中配置。

設(shè)置圓角

可使用以下兩種方式:

  1. 默認(rèn)使用一個(gè)shader繪制圓角,但是僅僅占位圖所要顯示的圖有圓角效果。失敗示意圖和重下載示意圖無(wú)圓角效果。
  2. 疊加一個(gè)solid color來(lái)繪制圓角。但是背景需要固定成指定的顏色。在XML中指定 roundWithOverlayColor, 或者通過(guò)調(diào)用setOverlayColor來(lái)完成此設(shè)定。

XML中配置

SimpleDraweeView 支持如下幾種圓角配置:

<com.facebook.drawee.view.SimpleDraweeView
   ...
   fresco:roundedCornerRadius="5dp"
   fresco:roundBottomLeft="false"
   fresco:roundBottomRight="false"
   fresco:roundWithOverlayColor="@color/blue"
   fresco:roundingBorderWidth="1dp"
   fresco:roundingBorderColor="@color/red"

代碼中配置

在創(chuàng)建 DraweeHierarchy 時(shí),可以給GenericDraweeHierarchyBuilder指定一個(gè) RoundingParams 用來(lái)繪制圓角效果。

RoundingParams roundingParams = RoundingParams.fromCornersRadius(7f);
roundingParams.setOverlayColor(R.color.green);
// 或用 fromCornersRadii 以及 asCircle 方法
genericDraweeHierarchyBuilder
    .setRoundingParams(roundingParams);

你也可以在運(yùn)行時(shí),改變圓角效果

RoundingParams roundingParams = 
    mSimpleDraweeView.getHierarchy().getRoundingParams();
roundingParams.setBorder(R.color.red, 1.0);
roundingParams.setRoundAsCircle(true);
mSimpleDraweeView.getHierarchy().setRoundingParams(roundingParams);

在運(yùn)行時(shí),不能改變呈現(xiàn)方式: 原本是圓角,不能改為圓圈。

使用ControllerBuilder

SimpleDraweeView 有兩個(gè)方法可以設(shè)置所要加載顯示圖片,簡(jiǎn)單的方法就是setImageURI。

如果你需要對(duì)加載顯示的圖片做更多的控制和定制,那就需要用到 DraweeController,本頁(yè)說(shuō)明如何使用。

DraweeController

首先,創(chuàng)建一個(gè)DraweeController, 然后傳遞圖片加載請(qǐng)求給 PipelineDraweeControllerBuilder

隨后,你可以控制controller的其他選項(xiàng)了:

ControllerListener listener = new BaseControllerListener() {...}
?
DraweeController controller = Fresco.newDraweeControllerBuilder()
    .setUri(uri)
    .setTapToRetryEnabled(true)
    .setOldController(mSimpleDraweeView.getController())
    .setControllerListener(listener)
    .build();
?
mSimpleDraweeView.setController(controller);

在指定一個(gè)新的controller的時(shí)候,使用setOldController,這可節(jié)省不必要的內(nèi)存分配。

自定義圖片加載請(qǐng)求

在更進(jìn)一步的用法中,你需要給Image pipeline 發(fā)送一個(gè)ImageRequest。下面是一個(gè)圖片加載后,使用后處理器(postprocessor) 進(jìn)行圖片后處理的例子.

Uri uri;
Postprocessor myPostprocessor = new Postprocessor() { ... }
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    .setPostprocessor(myPostprocessor)
    .build();
?
DraweeController controller = Fresco.newDraweeControllerBuilder()
    .setImageRequest(request)
    .setOldController(mSimpleDraweeView.getController())
    // 其他設(shè)置
    .build();

漸進(jìn)式JPEG圖

注意: 本頁(yè)提及的API僅是初步設(shè)計(jì),后續(xù)可能變動(dòng)

Fresco 支持漸進(jìn)式的網(wǎng)絡(luò)JPEG圖。在開始加載之后,圖會(huì)從模糊到清晰漸漸呈現(xiàn)。

你可以設(shè)置一個(gè)清晰度標(biāo)準(zhǔn),在未達(dá)到這個(gè)清晰度之前,會(huì)一直顯示占位圖。

漸進(jìn)式JPEG圖僅僅支持網(wǎng)絡(luò)圖。

初始化

配置Image pipeline時(shí) 需要傳遞一個(gè) ProgressiveJpegConfig 的實(shí)例。

這個(gè)實(shí)例需要完成兩個(gè)事情:1. 返回下一個(gè)需要解碼的掃描次數(shù)2. 確定多少個(gè)掃描次數(shù)之后的圖片才能開始顯示。

下面的實(shí)例中,為了實(shí)現(xiàn)節(jié)省CPU,并不是每個(gè)掃描都進(jìn)行解碼。

注意:

  • 每次解碼完之后,調(diào)用getNextScanNumberToDecode, 等待掃描值大于返回值,才有可能進(jìn)行解碼。

假設(shè),隨著下載的進(jìn)行,下載完的掃描序列如下: 1, 4, 5, 10。那么:

  1. 首次調(diào)用getNextScanNumberToDecode返回為2, 因?yàn)槌跏紩r(shí),解碼的掃描數(shù)為0。
  2. 那么1將不會(huì)解碼,下載完成4個(gè)掃描時(shí),解碼一次。下個(gè)解碼為掃描數(shù)為6
  3. 5不會(huì)解碼,10才會(huì)解碼
ProgressiveJpegConfig pjpegConfig = new ProgressiveJpegConfig() {
  @Override
  public int getNextScanNumberToDecode(int scanNumber) {
    return scanNumber + 2;
  }    
?
  public QualityInfo getQualityInfo(int scanNumber) {
    boolean isGoodEnough = (scanNumber >= 5);
    return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
  }
}
?
ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
    .setProgressiveJpegConfig(pjpeg)
    .build();

除了自己實(shí)現(xiàn)ProgressiveJpegConfig, 也可以直接使用 SimpleProgressiveJpegConfig

At Request Time

目前,我們必須顯式地在加載時(shí),允許漸進(jìn)式JPEG圖片加載。

Uri uri;
ImageRequest request = ImageRequestBuilder
    .newBuilderWithSource(uri)
    .setProgressiveRenderingEnabled(true)
    .build();
PipelineDraweeController controller = Fresco.newControllerBuilder()
    .setImageRequest(requests)
    .setOldController(mSimpleDraweeView.getController())
    .build();
?
mSimpleDraweeView.setController(controller);

我們希望在后續(xù)的版本中,在setImageURI方法中可以直接支持漸進(jìn)式圖片加載。

動(dòng)畫圖(gif)

Fresco 支持GIF和WebP 格式圖片;支持WebP 格式的動(dòng)畫圖也支持(包括擴(kuò)展WebP 格式),支持2.3及其以后那些沒有原生WebP支持的系統(tǒng)。

設(shè)置動(dòng)畫圖自動(dòng)播放

如果你希望圖片下載完之后自動(dòng)播放,同時(shí),當(dāng)View從屏幕移除時(shí),停止播放,只需要在image request 中簡(jiǎn)單設(shè)置,如下:

Uri uri;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    .setAutoPlayAnimation(true)
    . // other setters
    .build();
?
DraweeController controller = Fresco.newDraweeControllerBuilder()
    .setImageRequest(request)
    . // other setters
    .build();
mSimpleDraweeView.setController(controller);

手動(dòng)控制動(dòng)畫圖播放

也許,你希望在圖片加載完之后,手動(dòng)控制動(dòng)畫的播放,那么這樣做:

ControllerListener controllerListener = new BaseControllerListener() {
    @Override
    public void onFinalImageSet(
        String id,
        @Nullable ImageInfo imageInfo,
        @Nullable Animatable anim) {
    if (anim != null) {
      // 根據(jù)業(yè)務(wù)邏輯,在合適的時(shí)機(jī)播放動(dòng)畫。
    }
};
?
Uri uri;
PipelineDraweeController controller = Fresco.newControllerBuilder()
    .setControllerListener(controllerListener)
    .setUri(uri);
    // other setters
    .build();
mSimpleDraweeView.setController(controller);

另外,controller提供對(duì)Animatable 的訪問。

如果有可用動(dòng)畫的話,可對(duì)動(dòng)畫進(jìn)行靈活的控制:

Animatable animation = mSimpleDraweeView.getController().getAnimatable();
if (animation != null) {
  // 開始播放
  animation.start();
  // 一段時(shí)間之后,根據(jù)業(yè)務(wù)邏輯,停止播放
  animation.stop();
}

多圖請(qǐng)求及圖片復(fù)用

多圖請(qǐng)求需 自定義ImageRequest.

先顯示低分辨率的圖,然后是高分辨率的圖

如果你要顯示一張高分辨率的圖,但是這張圖下載比較耗時(shí)。你可以在下載前,先提供一張很快能下載完的小縮略圖。這比一直顯示占位圖,用戶體驗(yàn)會(huì)好很多。

這時(shí),你可以設(shè)置兩個(gè)圖片的URI,一個(gè)是低分辨率的縮略圖,一個(gè)是高分辨率的圖。

Uri lowResUri, highResUri;
PipelineDraweeController controller = Fresco.newControllerBuilder()
    .setLowResImageRequest(ImageRequest.fromUri(lowResUri))
    .setImageRequest(ImageRequest.fromUri(highResUri))
    .setOldController(mSimpleDraweeView.getController())
    .build();
mSimpleDraweeView.setController(controller);

縮略圖預(yù)覽

本功能僅支持本地URI,并且是JPEG圖片格式

如果本地JPEG圖,有EXIF的縮略圖,image pipeline 會(huì)立刻返回一個(gè)縮略圖。完整的清晰大圖,在decode完之后再顯示。

Uri uri;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    .setLocalThumbnailPreviewsEnabled(true)
    .build();
?
PipelineDraweeController controller = Fresco.newControllerBuilder()
    .setImageRequest(request)
    .setOldController(mSimpleDraweeView.getController())
    .build();
mSimpleDraweeView.setController(controller);

本地圖片復(fù)用

大部分的時(shí)候,一個(gè)圖片可能會(huì)對(duì)應(yīng)有多個(gè)URI,比如:

  • 拍照上傳。本地圖片較大,上傳的圖片較小。上傳完成之后的圖片,有一個(gè)url,如果要加載這個(gè)url,可直接加載本地圖片。
  • 本地已經(jīng)有600x600尺寸的大圖了,需要顯示100x100的小圖

對(duì)于一個(gè)URI,image pipeline 會(huì)依次檢查內(nèi)存,磁盤,如果沒有從網(wǎng)絡(luò)下載。

而對(duì)于一個(gè)圖片的多個(gè)URI,image pipeline 會(huì)先檢查他們是否在內(nèi)存中。如果沒有任何一個(gè)是在內(nèi)存中的,會(huì)檢查是否在本地存儲(chǔ)中。如果也沒有,才會(huì)執(zhí)行網(wǎng)絡(luò)下載。

但凡有任何一個(gè)檢查發(fā)現(xiàn)在內(nèi)存或者在本地存儲(chǔ)中,都會(huì)進(jìn)行復(fù)用。列表順序就是要顯示的圖片的優(yōu)先順序。

使用時(shí),創(chuàng)建一個(gè)image request 列表,然后傳給ControllerBuilder:

Uri uri1, uri2;
ImageRequest request = ImageRequest.fromUri(uri1);
ImageRequest request2 = ImageRequest.fromUri(uri2);
ImageRequest[] requests = { request1, request2 };
?
PipelineDraweeController controller = Fresco.newControllerBuilder()
    .setFirstAvailableImageRequests(requests)
    .setOldController(mSimpleDraweeView.getController())
    .build();
mSimpleDraweeView.setController(controller);

監(jiān)聽下載事件

你也許想在圖片下載完成或者下載失敗之后,做一些其他事情。

圖片是后臺(tái)線程異步加載的,我們可以使用一個(gè)ControllerListener實(shí)現(xiàn)事件的監(jiān)聽。

_在監(jiān)聽事件回調(diào)時(shí),無(wú)法修改圖片,如果需要修改圖片,可使用后處理器(Postprocessor)

~~~ ControllerListener controllerListener = new BaseControllerListener() {
@Override
public void onFinalImageSet(
String id,
@Nullable ImageInfo imageInfo,
@Nullable Animatable anim) {
if (imageInfo == null) {
return;
}
QualityInfo qualityInfo = imageInfo.getQualityInfo();
FLog.d("Final image received! " +
"Size %d x %d",
"Quality level %d, good enough: %s, full quality: %s",
imageInfo.getWidth(),
imageInfo.getHeight(),
qualityInfo.getQuality(),
qualityInfo.isOfGoodEnoughQuality(),
qualityInfo.isOfFullQuality());
}
?
@Override
public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
FLog.d("Intermediate image received");
}
?
@Override
public void onFailure(String id, Throwable throwable) {
FLog.e(getClass(), throwable, "Error loading %s", id)
}
};
?
Uri uri;
DraweeController controller = Fresco.newControllerBuilder()
.setControllerListener(controllerListener)
.setUri(uri);
// other setters
.build();
mSimpleDraweeView.setController(controller);


對(duì)所有的圖片加載,`onFinalImageSet` 或者 `onFailure` 都會(huì)被觸發(fā)。前者在成功時(shí),后者在失敗時(shí)。

如果允許呈現(xiàn)[漸進(jìn)式JPEG](#),同時(shí)圖片也是漸進(jìn)式圖片,`onIntermediateImageSet`會(huì)在每個(gè)掃描被解碼后回調(diào)。具體圖片的那個(gè)掃描會(huì)被解碼,參見[漸進(jìn)式JPEG圖](#)

### 縮放和旋轉(zhuǎn)圖片

使用這個(gè)功能需要直接[創(chuàng)建 image request](#)。

### 縮放圖片

#### 什么時(shí)候該修改圖片尺寸

一般地,當(dāng)所要顯示的圖片和顯示區(qū)域大小不一致時(shí),會(huì)按以下方式進(jìn)行處理。

1. 從服務(wù)器下載小一些的圖片
1. 顯示時(shí)縮放圖片
1. 調(diào)整圖片尺寸大小

對(duì)于一個(gè)圖片,如果服務(wù)器支持不同尺寸的縮略圖,那么每次下載都選擇尺寸最匹配的圖片,這個(gè)不僅節(jié)省數(shù)據(jù)流量也節(jié)約本地儲(chǔ)存和CPU。

如果服務(wù)器不支持,或者處理本地圖片的話,第二個(gè)選擇是[使用縮放類型](#)??s放是用Androi內(nèi)置的功能使圖像和顯示邊界相符。在4.0之后,支持硬件加速。這在大部分情況下是最快,同時(shí)也是最高效的顯示一張和顯示邊界大小相符的圖片的方式。首先指定`layout_width`和`layout_width`為指定值,然后指定[縮放類型](#)

但當(dāng)所要顯示的圖片比顯示區(qū)域大許多的時(shí)候,不推薦這樣做,縮放過(guò)程會(huì)導(dǎo)致大量的內(nèi)存消耗。

這時(shí),需要改變圖片尺寸。

#### 修改圖片尺寸

調(diào)整大小并不是修改原來(lái)的文件,而是在解碼之前,在native內(nèi)存中修改。

這個(gè)縮放方法,比Android內(nèi)置的縮放范圍更大。Android相機(jī)生成的照片一般尺寸都很大,需要調(diào)整大小之后才能被顯示。

目前,僅僅支持JPEG格式的圖片,同時(shí),大部分的Android系統(tǒng)相機(jī)圖片都是JPEG的。

如果要修改圖片尺寸,創(chuàng)建`ImageRequest`時(shí),提供一個(gè) ResizeOptions:

~~~java
Uri uri = "file:///mnt/sdcard/MyApp/myfile.jpg";
int width = 50, height = 50;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    .setResizeOptions(new ResizeOptions(width, height))
    .build();
PipelineDraweeController controller = Fresco.newDraweeControllerBuilder()
    .setOldController(mDraweeView.getController())
    .setImageRequest(request)
    .build();
mSimpleDraweeView.setController(controller);

自動(dòng)旋轉(zhuǎn)

如果看到的圖片是側(cè)著的,用戶是難受的。許多設(shè)備會(huì)在JPEG文件的metadata中記錄下照片的方向。如果你想圖片呈現(xiàn)的方向和設(shè)備屏幕的方向一致,你可以簡(jiǎn)單地這樣做到:

ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    .setAutoRotateEnabled(true)
    .build();
// as above

修改圖片

有時(shí),我們想對(duì)從服務(wù)器下載,或者本地的圖片做些修改,比如在某個(gè)坐標(biāo)統(tǒng)一加個(gè)網(wǎng)格什么的。這時(shí)使用后處理器(Postprocessor)便可達(dá)到目的。

例子:

給圖片加個(gè)網(wǎng)格:

Uri uri;
Postprocessor redMeshPostprocessor = new Postprocessor() { 
  @Override
  public String getName() {
    return "redMeshPostprocessor";
  }
?
  @Override
  public void process(Bitmap bitmap) {
    for (int x = 0; x < bitmap.getWidth(); x+=2) {
      for (int y = 0; y < bitmap.getHeight(); y+=2) {
        bitmap.setPixel(x, y, Color.RED);
      }
    }
  }
}
?
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    .setPostprocessor(redMeshPostprocessor)
    .build();
?
PipelineDraweeController controller = Fresco.newDraweeControllerBuilder()
    .setImageRequest(request)
    .setOldController(mSimpleDraweeView.getOldController())
    // other setters as you need
    .build();
mSimpleDraweeView.setController(controller);
注意點(diǎn)

圖片在進(jìn)入后處理器(postprocessor)的圖片是原圖的一個(gè)完整拷貝,原來(lái)的圖片不受修改的影響。在5.0以前的機(jī)器上,拷貝后的圖片也在native內(nèi)存中。

在開始一個(gè)圖片顯示時(shí),即使是反復(fù)顯示同一個(gè)圖片,在每次進(jìn)行顯示時(shí),都需要指定后處理器。

對(duì)于同一個(gè)圖片,每次顯示,可以使用不同的后處理器。

Repeated Postprocessors

如果想對(duì)同一個(gè)圖片進(jìn)行多次后處理,那么繼承 BaseRepeatedPostprocessor 即可。該類有一個(gè)update方法,需要執(zhí)行后處理時(shí),調(diào)用該方法即可。

下面的例子展示了在運(yùn)行時(shí),后處理改變圖片網(wǎng)格的顏色:

public class MeshPostprocessor extends BaseRepeatedPostprocessor { 
  private int mColor = Color.TRANSPARENT;
?
  public void setColor(int color) {
    mColor = color;
    update();
  }
?
  @Override
  public String getName() {
    return "meshPostprocessor";
  }
?
  @Override
  public void process(Bitmap bitmap) {
    for (int x = 0; x < bitmap.getWidth(); x+=2) {
      for (int y = 0; y < bitmap.getHeight(); y+=2) {
        bitmap.setPixel(x, y, mColor);
      }
    }
  }
}
MeshPostprocessor meshPostprocessor = new MeshPostprocessor();
?
// setPostprocessor as in above example
?
// 改變顏色
meshPostprocessor.setColor(Color.RED);
meshPostprocessor.setColor(Color.BLUE);

每個(gè)image request, 仍舊只有一個(gè)Postprocessor,但是這個(gè)后處理器是狀態(tài)相關(guān)了。

圖片請(qǐng)求

如果你需要的ImageRequest僅僅是一個(gè)URI,那么ImageRequest.fromURI就足夠了,在多圖請(qǐng)求及圖片復(fù)用中,有這樣的用法。

否則,你需要ImageRequestBuilder來(lái)做更多的事情。

Uri uri;
?
ImageDecodeOptions decodeOptions = ImageDecodeOptions.newBuilder()
    .setBackgroundColor(Color.GREEN)
    .build();
?
ImageRequest request = ImageRequestBuilder
    .newBuilderWithSource(uri)
    .setAutoRotateEnabled(true)
    .setLocalThumbnailPreviewsEnabled(true)
    .setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
    .setProgressiveRenderingEnabled(false)
    .setResizeOptions(new ResizeOptions(width, height))
    .build();
ImageRequest 的屬性和成員
最低請(qǐng)求級(jí)別

Image pipeline 加載圖片時(shí)有一套明確的請(qǐng)求流程

  1. 檢查內(nèi)存緩存,有如,立刻返回。這個(gè)操作是實(shí)時(shí)的。
  2. 檢查未解碼的圖片緩存,如有,解碼并返回。
  3. 檢查磁盤緩存,如果有加載,解碼,返回。
  4. 下載或者加載本地文件。調(diào)整大小和旋轉(zhuǎn)(如有),解碼并返回。對(duì)于網(wǎng)絡(luò)圖來(lái)說(shuō),這一套流程下來(lái)是最耗時(shí)的。

setLowestPermittedRequestLevel允許設(shè)置一個(gè)最低請(qǐng)求級(jí)別,請(qǐng)求級(jí)別和上面對(duì)應(yīng)地有以下幾個(gè)取值:

  • BITMAP_MEMORY_CACHE
  • ENCODED_MEMORY_CACHE
  • DISK_CACHE
  • FULL_FETCH

如果你需要立即取到一個(gè)圖片,或者在相對(duì)比較短時(shí)間內(nèi)取到圖片,否則就不顯示的情況下,這非常有用。

自定義View

DraweeHolders

總有一些時(shí)候,DraweeViews是滿足不了需求的,在展示圖片的時(shí)候,我們還需要展示一些其他的內(nèi)容,或者支持一些其他的操作。在同一個(gè)View里,我們可能會(huì)想顯示一張或者多張圖。

在自定義View中,F(xiàn)resco 提供了兩個(gè)類來(lái)負(fù)責(zé)圖片的展現(xiàn):

  • DraweeHolder 單圖情況下用。
  • MultiDraweeHolder 多圖情況下用。
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)