第 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"
  />
必须设置layout_width和layout_height

如果没有在XML中声明这两个属性,将无法正确加载图像。

wrap_content

Drawees 不支持 wrap_content 属性。

所下载的图像可能和占位图尺寸不一致,如果设置出错图或者重试图的话,这些图的尺寸也可能和所下载的图尺寸不一致。

如果大小不一致,图像下载完之后,假设如果是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

设置或更改要显示的图片

mSimpleDraweeView.setImageURI(uri);

如果要更加复杂的配置,可使用ControllerBuilder;

自定义显示图

一般情况下,在XML设置显示效果即可, 如果想更多定制化,可以这样:

创建一个 builder 然后设置给 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,请不要多次调用setHierarchy,即使这个View是可回收的。创建 DraweeHierarchy 的较为耗时的一个过程,应该多次利用。

如果要改变所要显示的图片可使用setController 或者 setImageURI

修改 DraweeHierarchy

DraweeHierarchy 的一些属性可以在运行时改变。

要改变这些属性,首先获取一个引用:

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

修改占位图为资源id:

hierarchy.setPlaceholderImage(R.drawable.placeholderId);

或者修改为一个 Drawable:

Drawable drawable; 
// 创建一个drawable
hierarchy.setPlaceholderImage(drawable);
修改显示的图像

修改缩放类型:

hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_INSIDE);

当然,如果修改为 focusCrop, 需要指定一个居中点:

hierarchy.setActualImageFocusPoint(point);

或者设置一个color filter:

ColorFilter filter;
// 创建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:

除了圆角显示方式(原来为圆角的不能修改为圆圈,反之亦然),其他圆角相关的呈现参数, 具体参见这里 是可以动态修改的。

如下: 获取DraweeHierarchy的圆角显示参数,修改圆角半径为10。

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

Drawee的各种效果配置

内容导航

定义

本页说明如何设置实现不同的图片呈现效果。

除了要加载的图片,其他各个设置都可以在xml中指定。在xml中指定的时候,可以是 drawable/下的资源,也可以颜色。

在Java 代码中也可以指定。如果需要 通过程序设定 的话会接触到这个类: GenericDraweeHierarchyBuilder

通过代码设置是,设置的值可以是资源id,也可以是 Drawable 的子类。

创建完 GenericDraweeHierarchy 之后,也可以通过该类的相关方法,重新设置一些效果。

大多数的用户呈现不同效果的drawables都是可以缩放的.

设置要加载的图

除了需要加载的图片是真正必须的,其他的都是可选的。如前所述,图片可以来自多个地方。

所需加载的图片实际是DraweeController的一个属性,而不是 DraweeHierarchy 的属性。

可使用setImageURI方法或者通过设置 DraweeController 来进行设置。

对于要加载的图片,除了可以设置缩放类型外,DraweeHierarchy 还公开出一些其他方法用来控制显示效果:

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

默认的缩放类型是: centerCrop

占位图(Placeholder)

在调用setController 或者 setImageURI 之后,占位图开始显示,直到图片加载完成。

对于渐进式格式的JPEG图片,占位图会显示直到满足已加载的图片解析度到达设定值。

XML 中属性值: placeholderImage
Hierarchy builder中的方法: setPlaceholderImage
Hierarchy method: setPlaceholderImage
默认值: a transparent ColorDrawable
默认缩放类型: centerInside

设置加载失败占位图

如果URI是无效的,或者下载过程中网络不可用,将会导致加载失败。当加载图片出错时,你可以设置一个出错提示图片。

XML 中属性值: failureImage
Hierarchy builder中的方法: setFailureImage
默认值: The placeholder image
默认缩放类型: centerInside

点击重新加载图

在加载失败时,可以设置点击重新加载。这时提供一个图片,加载失败时,会显示这个图片(而不是失败提示图片),提示用户点击重试。

ControllerBuilder 中如下设置:

.setTapToRetryEnabled(true)

加载失败时,image pipeline 会重试四次;如果还是加载失败,则显示加载失败提示图片。

XML 中属性值: retryImage
Hierarchy builder中的方法: setRetryImage
默认值: The placeholder image
默认缩放类型: centerInside

显示一个进度条

设置一个进度条图片,提示用户正在加载。目前,进度条仅仅是提示正在loading,和加载进度无关。

XML 中属性值: progressBarImage
Hierarchy builder中的方法: setProgressBarImage
默认值: None
默认缩放类型: centerInside

背景

背景图会最先绘制,在XML中只可以指定一个背景图,但是在JAVA代码中,可以指定多个背景图。

当指定一个背景图列表的时候,列表中的第一项会被首先绘制,绘制在最下层,然后依次往上绘制。

背景图片不支持缩放类型,会被强制到Drawee尺寸大小。

XML 中属性值: backgroundImage
Hierarchy builder中的方法: setBackground,``setBackgrounds
默认值: None
默认缩放类型: N/A

设置叠加图(Overlay)

叠加图会最后被绘制。

和背景图一样,XML中只可以指定一个,如果想指定多个,可以通过JAVA代码实现。

当指定的叠加图是一个列表的时候,列表第一个元素会被先绘制,最后一个元素最后被绘制到最上层。

同样的,不支持各种缩放类型。

XML 中属性值: overlayImage
Hierarchy builder中的方法: setOverlay,``setOverlays
默认值: None
默认缩放类型: N/A

设置按压状态下的叠加图

同样不支持缩放,用户按压DraweeView时呈现。

XML 中属性值: pressedStateOverlayImage
Hierarchy builder中的方法: setPressedStateOverlay
默认值: None
默认缩放类型: N/A

缩放

对于 Drawee 的各种效果配置,其中一些是支持缩放类型的。

可用的缩放类型

类型 描述
center 居中,无缩放
centerCrop 保持宽高比缩小或放大,使得两边都大于或等于显示边界。居中显示。
focusCrop 同centerCrop, 但居中点不是中点,而是指定的某个点
centerInside 使两边都在显示边界内,居中显示。
如果图尺寸大于显示边界,则保持长宽比缩小图片。
fitCenter 保持宽高比,缩小或者放大,使得图片完全显示在显示边界内。居中显示
fitStart 同上。但不居中,和显示边界左上对齐
fitEnd 同fitCenter, 但不居中,和显示边界右下对齐
fitXY 不保存宽高比,填充满显示边界
none 如要使用tile mode显示, 需要设置为none

这些缩放类型和Android ImageView 支持的缩放类型几乎一样.

唯一不支持的缩放类型是matrix. Fresco 提供了focusCrop 作为补充。通常这个缩放效果更佳。

focusCrop

centerCrop缩放模式会保持长宽比,缩放图片,填充满显示边界,居中显示。这个缩放模式在通常情况下很有用。

但是对于人脸等图片时,一味地居中显示,这个模式可能会裁剪掉一些有用的信息。

以人脸图片为例,借助一些类库,我们可以识别出人脸所在位置。如果可以设置以人脸位置居中裁剪显示,那么效果会好很多。

Fresco的focusCrop缩放模式正是为此而设计。只要提供一个居中聚焦点,显示时就会尽量以此点为中心。

居中点是以相对方式给出的,比如(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 设置为none.

圆角和圆圈

Drawee 轻松支持圆角显示,并且显示圆角时,并不复制和修改Bitmap对象,那样太耗费内存。

圆角

圆角实际有2中呈现方式:

  1. 圆圈 - 设置roundAsCircle为true
  2. 圆角 - 设置roundedCornerRadius

设置圆角时,支持4个角不同的半径。XML中无法配置,但可在Java代码中配置。

设置圆角

可使用以下两种方式:

  1. 默认使用一个shader绘制圆角,但是仅仅占位图所要显示的图有圆角效果。失败示意图和重下载示意图无圆角效果。
  2. 叠加一个solid color来绘制圆角。但是背景需要固定成指定的颜色。在XML中指定 roundWithOverlayColor, 或者通过调用setOverlayColor来完成此设定。

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"

代码中配置

在创建 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);

在运行时,不能改变呈现方式: 原本是圆角,不能改为圆圈。

使用ControllerBuilder

SimpleDraweeView 有两个方法可以设置所要加载显示图片,简单的方法就是setImageURI

如果你需要对加载显示的图片做更多的控制和定制,那就需要用到 DraweeController,本页说明如何使用。

DraweeController

首先,创建一个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,这可节省不必要的内存分配。

自定义图片加载请求

在更进一步的用法中,你需要给Image pipeline 发送一个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())
    // 其他设置
    .build();

渐进式JPEG图

注意: 本页提及的API仅是初步设计,后续可能变动

Fresco 支持渐进式的网络JPEG图。在开始加载之后,图会从模糊到清晰渐渐呈现。

你可以设置一个清晰度标准,在未达到这个清晰度之前,会一直显示占位图。

渐进式JPEG图仅仅支持网络图。

初始化

配置Image pipeline时 需要传递一个 ProgressiveJpegConfig 的实例。

这个实例需要完成两个事情:1. 返回下一个需要解码的扫描次数2. 确定多少个扫描次数之后的图片才能开始显示。

下面的实例中,为了实现节省CPU,并不是每个扫描都进行解码。

注意:

  • 每次解码完之后,调用getNextScanNumberToDecode, 等待扫描值大于返回值,才有可能进行解码。

假设,随着下载的进行,下载完的扫描序列如下: 1, 4, 5, 10。那么:

  1. 首次调用getNextScanNumberToDecode返回为2, 因为初始时,解码的扫描数为0。
  2. 那么1将不会解码,下载完成4个扫描时,解码一次。下个解码为扫描数为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();

除了自己实现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);

我们希望在后续的版本中,在setImageURI方法中可以直接支持渐进式图片加载。

动画图(gif)

Fresco 支持GIF和WebP 格式图片;支持WebP 格式的动画图也支持(包括扩展WebP 格式),支持2.3及其以后那些没有原生WebP支持的系统。

设置动画图自动播放

如果你希望图片下载完之后自动播放,同时,当View从屏幕移除时,停止播放,只需要在image request 中简单设置,如下:

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) {
      // 根据业务逻辑,在合适的时机播放动画。
    }
};
 
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();
  // 一段时间之后,根据业务逻辑,停止播放
  animation.stop();
}

多图请求及图片复用

多图请求需 自定义ImageRequest.

先显示低分辨率的图,然后是高分辨率的图

如果你要显示一张高分辨率的图,但是这张图下载比较耗时。你可以在下载前,先提供一张很快能下载完的小缩略图。这比一直显示占位图,用户体验会好很多。

这时,你可以设置两个图片的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,可直接加载本地图片。
  • 本地已经有600x600尺寸的大图了,需要显示100x100的小图

对于一个URI,image pipeline 会依次检查内存,磁盘,如果没有从网络下载。

而对于一个图片的多个URI,image pipeline 会先检查他们是否在内存中。如果没有任何一个是在内存中的,会检查是否在本地存储中。如果也没有,才会执行网络下载。

但凡有任何一个检查发现在内存或者在本地存储中,都会进行复用。列表顺序就是要显示的图片的优先顺序。

使用时,创建一个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);

监听下载事件

你也许想在图片下载完成或者下载失败之后,做一些其他事情。

图片是后台线程异步加载的,我们可以使用一个ControllerListener实现事件的监听。

_在监听事件回调时,无法修改图片,如果需要修改图片,可使用后处理器(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` 都会被触发。前者在成功时,后者在失败时。

如果允许呈现[渐进式JPEG](#),同时图片也是渐进式图片,`onIntermediateImageSet`会在每个扫描被解码后回调。具体图片的那个扫描会被解码,参见[渐进式JPEG图](#)

### 缩放和旋转图片

使用这个功能需要直接[创建 image request](#)。

### 缩放图片

#### 什么时候该修改图片尺寸

一般地,当所要显示的图片和显示区域大小不一致时,会按以下方式进行处理。

1. 从服务器下载小一些的图片
1. 显示时缩放图片
1. 调整图片尺寸大小

对于一个图片,如果服务器支持不同尺寸的缩略图,那么每次下载都选择尺寸最匹配的图片,这个不仅节省数据流量也节约本地储存和CPU。

如果服务器不支持,或者处理本地图片的话,第二个选择是[使用缩放类型](#)。缩放是用Androi内置的功能使图像和显示边界相符。在4.0之后,支持硬件加速。这在大部分情况下是最快,同时也是最高效的显示一张和显示边界大小相符的图片的方式。首先指定`layout_width`和`layout_width`为指定值,然后指定[缩放类型](#)

但当所要显示的图片比显示区域大许多的时候,不推荐这样做,缩放过程会导致大量的内存消耗。

这时,需要改变图片尺寸。

#### 修改图片尺寸

调整大小并不是修改原来的文件,而是在解码之前,在native内存中修改。

这个缩放方法,比Android内置的缩放范围更大。Android相机生成的照片一般尺寸都很大,需要调整大小之后才能被显示。

目前,仅仅支持JPEG格式的图片,同时,大部分的Android系统相机图片都是JPEG的。

如果要修改图片尺寸,创建`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);

自动旋转

如果看到的图片是侧着的,用户是难受的。许多设备会在JPEG文件的metadata中记录下照片的方向。如果你想图片呈现的方向和设备屏幕的方向一致,你可以简单地这样做到:

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

修改图片

有时,我们想对从服务器下载,或者本地的图片做些修改,比如在某个坐标统一加个网格什么的。这时使用后处理器(Postprocessor)便可达到目的。

例子:

给图片加个网格:

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内存中。

在开始一个图片显示时,即使是反复显示同一个图片,在每次进行显示时,都需要指定后处理器。

对于同一个图片,每次显示,可以使用不同的后处理器。

Repeated Postprocessors

如果想对同一个图片进行多次后处理,那么继承 BaseRepeatedPostprocessor 即可。该类有一个update方法,需要执行后处理时,调用该方法即可。

下面的例子展示了在运行时,后处理改变图片网格的颜色:

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,但是这个后处理器是状态相关了。

图片请求

如果你需要的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. 检查内存缓存,有如,立刻返回。这个操作是实时的。
  2. 检查未解码的图片缓存,如有,解码并返回。
  3. 检查磁盘缓存,如果有加载,解码,返回。
  4. 下载或者加载本地文件。调整大小和旋转(如有),解码并返回。对于网络图来说,这一套流程下来是最耗时的。

setLowestPermittedRequestLevel允许设置一个最低请求级别,请求级别和上面对应地有以下几个取值:

  • BITMAP_MEMORY_CACHE
  • ENCODED_MEMORY_CACHE
  • DISK_CACHE
  • FULL_FETCH

如果你需要立即取到一个图片,或者在相对比较短时间内取到图片,否则就不显示的情况下,这非常有用。

自定义View

DraweeHolders

总有一些时候,DraweeViews是满足不了需求的,在展示图片的时候,我们还需要展示一些其他的内容,或者支持一些其他的操作。在同一个View里,我们可能会想显示一张或者多张图。

在自定义View中,Fresco 提供了两个类来负责图片的展现:

  • DraweeHolder 单图情况下用。
  • MultiDraweeHolder 多图情况下用。
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号