第 2 章 DRAWEE 指南

2018-02-24 15:57 更新

在XML中使用Drawees

Drawees 具有極大的可定制性。

下面的例子給出了可以配置的各種選項:

<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中聲明這兩個屬性,將無法正確加載圖像。

wrap_content

Drawees 不支持 wrap_content 屬性。

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

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

固定寬高比

只有希望顯示的固定寬高比時,可以使用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);

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

自定義顯示圖

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

創(chuàng)建一個 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);

對于同一個View,請不要多次調(diào)用setHierarchy,即使這個View是可回收的。創(chuàng)建 DraweeHierarchy 的較為耗時的一個過程,應該多次利用。

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

修改 DraweeHierarchy

DraweeHierarchy 的一些屬性可以在運行時改變。

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

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

修改占位圖為資源id:

hierarchy.setPlaceholderImage(R.drawable.placeholderId);

或者修改為一個 Drawable:

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

修改縮放類型:

hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_INSIDE);

當然,如果修改為 focusCrop, 需要指定一個居中點:

hierarchy.setActualImageFocusPoint(point);

或者設(shè)置一個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:

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

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

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

Drawee的各種效果配置

內(nèi)容導航

定義

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

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

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

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

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

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

設(shè)置要加載的圖

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

所需加載的圖片實際是DraweeController的一個屬性,而不是 DraweeHierarchy 的屬性。

可使用setImageURI方法或者通過設(shè)置 DraweeController 來進行設(shè)置。

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

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

默認的縮放類型是: centerCrop

占位圖(Placeholder)

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

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

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

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

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

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

點擊重新加載圖

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

ControllerBuilder 中如下設(shè)置:

.setTapToRetryEnabled(true)

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

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

顯示一個進度條

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

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

背景

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

當指定一個背景圖列表的時候,列表中的第一項會被首先繪制,繪制在最下層,然后依次往上繪制。

背景圖片不支持縮放類型,會被強制到Drawee尺寸大小。

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

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

疊加圖會最后被繪制。

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

當指定的疊加圖是一個列表的時候,列表第一個元素會被先繪制,最后一個元素最后被繪制到最上層。

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

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

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

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

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

縮放

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

可用的縮放類型

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

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

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

focusCrop

centerCrop縮放模式會保持長寬比,縮放圖片,填充滿顯示邊界,居中顯示。這個縮放模式在通常情況下很有用。

但是對于人臉等圖片時,一味地居中顯示,這個模式可能會裁剪掉一些有用的信息。

以人臉圖片為例,借助一些類庫,我們可以識別出人臉所在位置。如果可以設(shè)置以人臉位置居中裁剪顯示,那么效果會好很多。

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

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

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

  fresco:actualImageScaleType="focusCrop"

在Java代碼中

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

none

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

圓角和圓圈

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

圓角

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

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

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

設(shè)置圓角

可使用以下兩種方式:

  1. 默認使用一個shader繪制圓角,但是僅僅占位圖所要顯示的圖有圓角效果。失敗示意圖和重下載示意圖無圓角效果。
  2. 疊加一個solid color來繪制圓角。但是背景需要固定成指定的顏色。在XML中指定 roundWithOverlayColor, 或者通過調(diào)用setOverlayColor來完成此設(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 時,可以給GenericDraweeHierarchyBuilder指定一個 RoundingParams 用來繪制圓角效果。

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

你也可以在運行時,改變圓角效果

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

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

使用ControllerBuilder

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

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

DraweeController

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

隨后,你可以控制controller的其他選項了:

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

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

自定義圖片加載請求

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

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();

漸進式JPEG圖

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

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

你可以設(shè)置一個清晰度標準,在未達到這個清晰度之前,會一直顯示占位圖。

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

初始化

配置Image pipeline時 需要傳遞一個 ProgressiveJpegConfig 的實例。

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

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

注意:

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

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

  1. 首次調(diào)用getNextScanNumberToDecode返回為2, 因為初始時,解碼的掃描數(shù)為0。
  2. 那么1將不會解碼,下載完成4個掃描時,解碼一次。下個解碼為掃描數(shù)為6
  3. 5不會解碼,10才會解碼
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();

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

At Request Time

目前,我們必須顯式地在加載時,允許漸進式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方法中可以直接支持漸進式圖片加載。

動畫圖(gif)

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

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

如果你希望圖片下載完之后自動播放,同時,當View從屏幕移除時,停止播放,只需要在image request 中簡單設(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);

手動控制動畫圖播放

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

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

另外,controller提供對Animatable 的訪問。

如果有可用動畫的話,可對動畫進行靈活的控制:

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

多圖請求及圖片復用

多圖請求需 自定義ImageRequest.

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

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

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

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

縮略圖預覽

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

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

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

本地圖片復用

大部分的時候,一個圖片可能會對應有多個URI,比如:

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

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

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

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

使用時,創(chuàng)建一個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)聽下載事件

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

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

_在監(jiān)聽事件回調(diào)時,無法修改圖片,如果需要修改圖片,可使用后處理器(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);


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

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

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

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

### 縮放圖片

#### 什么時候該修改圖片尺寸

一般地,當所要顯示的圖片和顯示區(qū)域大小不一致時,會按以下方式進行處理。

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

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

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

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

這時,需要改變圖片尺寸。

#### 修改圖片尺寸

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

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

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

如果要修改圖片尺寸,創(chuàng)建`ImageRequest`時,提供一個 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);

自動旋轉(zhuǎn)

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

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

修改圖片

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

例子:

給圖片加個網(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);
注意點

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

在開始一個圖片顯示時,即使是反復顯示同一個圖片,在每次進行顯示時,都需要指定后處理器。

對于同一個圖片,每次顯示,可以使用不同的后處理器。

Repeated Postprocessors

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

下面的例子展示了在運行時,后處理改變圖片網(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);

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

圖片請求

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

否則,你需要ImageRequestBuilder來做更多的事情。

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 的屬性和成員
最低請求級別

Image pipeline 加載圖片時有一套明確的請求流程

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

setLowestPermittedRequestLevel允許設(shè)置一個最低請求級別,請求級別和上面對應地有以下幾個取值:

  • BITMAP_MEMORY_CACHE
  • ENCODED_MEMORY_CACHE
  • DISK_CACHE
  • FULL_FETCH

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

自定義View

DraweeHolders

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

在自定義View中,F(xiàn)resco 提供了兩個類來負責圖片的展現(xiàn):

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號