GenericDraweeHierarchy构建图层

Fresco源码分析(2) – GenericDraweeHierarchy构建图层

作者:Desmond 转载请注明出处!

在本篇的内容中,作者将初步介绍Fresco是怎么构建图像层次的。

引言

DraweeHierarchy是所有Hierarchy的父接口,它内部只提供了一个基本而又不可缺失的功能:获取图层树的父节点图层。不过仅仅只有这个功能是不够的,Fresco紧接着用接口SettableHierarchy来继承它,声明一些具体的功能:

这几个函数都会在后面起到比较大的作用。 在接下来的内容中会介绍本节的主角:GenericDraweeHierarchy。它实现了SettableHierarchy接口,你可以从这个类中看到大部分Fresco处理图层的逻辑。

图层封装者 – GenericDraweeHierarchy

请记住这句话:GenericDraweeHierarchy只是负责装载每个图层信息的载体。如果你直接使用它去显示图片,那就意味着你将放弃Fresco提供的加载与缓存机制。你可以认为这么做之后SimpleDraweeView就退化成了一个简单的ImageView,只会将ArrayDrawable中的所有设置的图片按顺序显示出来。具体的细节我们将在Fresco源码分析(3) – DraweeView显示图层树中讨论。

首先看几个成员变量:

mPlaceholderImageIndex; mProgressBarImageIndex; mActualImageIndex; mRetryImageIndex; mFailureImageIndex; mControllerOverlayIndex;

简洁明了有木有!没错,这个GenericDraweeHierarchy就是封装与维护Drawable层次的家伙!你需要牢记以上这六种图层名字,它是Fresco的视图显示中最主要的六个图层。

建造者模式

如果你经常使用Fresco,你就会发现它的设计之中充斥着建造者模式。由于Fresco中的对象初始化经常是比较复杂的,建造者模式能为开发者在创建实例上省去很多功夫。

1GenericDraweeHierarchy的建造者是GenericDraweeHierarchyBuilder。它内部维持着许多图层属性,主要有这两种: – 默认的变量(渐变动画时间、ScaleType) – 程序的Resources实例 – 圆角矩形容器的一些参数 – 要放到每个图层容器中的Drawable实例及图层要应用的ScaleType、Matrix等等。

这个Builder内部有大量的getter与setter,你可以为每个图层指定Drawable、ScaleType,以及目标显示图层还可以设置Matrix、Focus(配合ScaleType为FOCUS_CROP时使用)、ColorFilter。

初始化图层

我们来看一下GenericDraweeHierarchy,从中能够理解Fresco是怎么初始化图层的。

GenericDraweeHierarchy(GenericDraweeHierarchyBuilder builder) {mResources = builder.getResources();// 获取圆角参数mRoundingParams = builder.getRoundingParams();.// 初始化图层数为0int numLayers = 0;int numBackgrounds = (builder.getBackgrounds() != null) ? builder.getBackgrounds().size() : 0;int backgroundsIndex = numLayers;numLayers += numBackgrounds;

在这段代码中我们可以看到最开始初始化的是背景图层(顶层图层),会根据是否传入背景图层来判断图层数是否增减。再接着往下看:

Drawable placeholderImageBranch = builder.getPlaceholderImage();if (placeholderImageBranch == null) {placeholderImageBranch = getEmptyPlaceholderDrawable();}placeholderImageBranch = maybeApplyRoundingBitmapOnly(mRoundingParams,mResources,placeholderImageBranch);placeholderImageBranch = maybeWrapWithScaleType(placeholderImageBranch,builder.getPlaceholderImageScaleType());mPlaceholderImageIndex = numLayers++;

在这段代码中,它对占位图层进行了以下处理: – 获取图层Drawable资源,如果没有设置,它将创建一个透明图层。 – 根据圆角参数对图片进行圆角处理。 – 将待显示的Drawable资源包装进一个ScaleTypeDrawable中,处理缩放逻辑(关于ScaleTypeDrawable可以参考Fresco源码分析(1) – 图像层次与各类Drawable)。 – 记录图层在ArrayDrawable中的index,图层数量加一。

我们再看看目标显示图层的处理逻辑,与占位图层的处理有什么区别:

Drawable actualImageBranch = null;mActualImageSettableDrawable = new SettableDrawable(mEmptyActualImageDrawable);actualImageBranch = mActualImageSettableDrawable;actualImageBranch = maybeWrapWithScaleType(actualImageBranch,builder.getActualImageScaleType(),builder.getActualImageFocusPoint());actualImageBranch = maybeWrapWithMatrix(actualImageBranch,builder.getActualImageMatrix());actualImageBranch.setColorFilter(builder.getActualImageColorFilter());mActualImageIndex = numLayers++;

与占位图层有区别的是它在显示图上多加了一了SettableDrawable容器(正常图层只有一个ScaleTypeDrawable容器),没有进行圆角处理。由于可以后续改变图像内容,它直接使用了默认的透明图来初始化图层,而且它还拥有ColorFilter、Matrix等特权。

需要注意的一点:在不显式指定图层内容的时候,占位图层、目标显示图层、控制覆盖图层将会创建透明图层实例,其他图层不会创建实例。 并且只有在指定内容的时候图层数量才会增加,,除此以外其他图层与占位图、目标图层的初始化没有什么区别。

在初始化完基本图层之后,那我们接着看余下初始化过程:

// overlaysint overlaysIndex = numLayers;int numOverlays =((builder.getOverlays() != null) ? builder.getOverlays().size() : 0) +((builder.getPressedStateOverlay() != null) ? 1 : 0);numLayers += numOverlays;// controller overlaymControllerOverlayIndex = numLayers++;

这部分是初始化覆盖图层及控制覆盖图层。如果没有设置覆盖图层,他们不会被初始化。不过控制覆盖图层是会被初始化成透明图层的。

// array of layersDrawable[] layers = new Drawable[numLayers];if (numBackgrounds > 0) {int index = 0;for (Drawable background : builder.getBackgrounds()) {layers[backgroundsIndex + index++] =maybeApplyRoundingBitmapOnly(mRoundingParams, mResources, background);}}if (mPlaceholderImageIndex >= 0) {layers[mPlaceholderImageIndex] = placeholderImageBranch;}// 各图层赋值if (mFailureImageIndex >= 0) {layers[mFailureImageIndex] = failureImageBranch;}if (numOverlays > 0) {int index = 0;if (builder.getOverlays() != null) {for (Drawable overlay : builder.getOverlays()) {layers[overlaysIndex + index++] = overlay;}}//按下时加在图片上的的覆盖图层if (builder.getPressedStateOverlay() != null) {layers[overlaysIndex + index++] = builder.getPressedStateOverlay();}}if (mControllerOverlayIndex >= 0) {layers[mControllerOverlayIndex] = mEmptyControllerOverlayDrawable;}接受失败也等于给了自己从零开始的机会,接受失败更是一种智者的宣言和呐喊;

GenericDraweeHierarchy构建图层

相关文章:

你感兴趣的文章:

标签云: