Fresco
是一個MVC模型,由三大組件構成,它們的對應關系如下所示:
M 所對應的 DraweeHierarchy
是一個有層次結構的數據結構,DraweeView
用來顯示位於 DraweeHierarchy
最頂層的圖像(top level drawable),DraweeController
則用來控制 DraweeHierarchy
的頂層圖像是哪一個。
o FadeDrawable (top level drawable) | +--o ScaleTypeDrawable | | | +--o BitmapDrawable | +--o ScaleTypeDrawable | +--o BitmapDrawable
三者的互動關系很簡單,DraweeView
把獲得的 Event
轉發給 Controller
,然後 Controller
根據 Event
來決定是否需要顯示和隱藏 (包括動畫)圖像,而這些圖像都存儲在 Hierarchy
中,最後 DraweeView
繪制時直接通過 getTopLevelDrawable
就可以獲取需要顯示的圖像。
需要注意的是,雖然現在最新的代碼中,DraweeView
還是繼承自 ImageView
,但是以後會直接繼承 View
,所以我們用 DraweeView
時,盡量不要使用 ImageView
的API,例如 setImageXxx
、setScaleType
,注釋裡也寫得很清楚。
Although ImageView is subclassed instead of subclassing View directly, this class does not suppZ喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcnQgSW1hZ2VWaWV3JnJzcXVvO3Mgc2V0SW1hZ2VYeHgsIHNldFNjYWxlVHlwZSBhbmQgc2ltaWxhciBtZXRob2RzLiBFeHRlbmRpbmcgSW1hZ2VWaWV3IGlzIGEgc2hvcnQgdGVybSBzb2x1dGlvbiBpbiBvcmRlciB0byBpbmhlcml0IHNvbWUgb2YgaXRzIGltcGxlbWVudGF0aW9uIChwYWRkaW5nIGNhbGN1bGF0aW9ucywgZXRjLikuIFRoaXMgY2xhc3MgaXMgbGlrZWx5IHRvIGJlIGNvbnZlcnRlZCB0byBleHRlbmQgVmlldyBkaXJlY3RseSBpbiB0aGUgZnV0dXJlLCBzbyA8c3Ryb25nPmF2b2lkIHVzaW5nIEltYWdlVmlldyZyc3F1bztzIG1ldGhvZHMgYW5kIHByb3BlcnRpZXM8L3N0cm9uZz4gKFQ1ODU2MTc1KS48L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD7TybnYz7XNvL/J0tS/tLP2o6w8Y29kZT5EcmF3ZWVWaWV3PC9jb2RlPiDW0LKiw7vT0CA8Y29kZT5EcmF3ZWVIaWVyYXJjaHk8L2NvZGU+ILrNIDxjb2RlPkRyYXdlZUNvbnRyb2xsZXI8L2NvZGU+IMDg0M21xLPJ1LGx5MG/o6y2+Na709DSu7j2IDxjb2RlPkRyYXdIb2xkZXI8L2NvZGU+IMDg0M21xCA8Y29kZT5tRHJhd0hvbGRlcjwvY29kZT6hozwvcD4NCjxwcmUgY2xhc3M9"brush:java;">
public class DraweeHolder
implements VisibilityCallback { // other properties private DH mHierarchy; private DraweeController mController = null; // methods }
DraweeHolder
存儲了mHierarchy
和mController
,FB 為什麼要這麼設計呢?注釋裡也寫得很清楚:Drawee users, should, as a rule, use DraweeView or its subclasses. There are situations where custom views are required, however, and this class is for those circumstances.
稍微解釋一下,這是一個解耦的設計,當我們不想使用
DraweeView
,通過ViewHolder
照樣可以使用其他兩個組件。比方說,自定義一個View
,然後像DraweeView
那樣,在View
中添加一個DrawHolder
的成員變量。再來看
DraweeView
的代碼:public class DraweeView
extends ImageView { // other methods and properties /** Sets the hierarchy. */ public void setHierarchy(DH hierarchy) { mDraweeHolder.setHierarchy(hierarchy); super.setImageDrawable(mDraweeHolder.getTopLevelDrawable()); } /** Sets the controller. */ public void setController(@Nullable DraweeController draweeController) { mDraweeHolder.setController(draweeController); super.setImageDrawable(mDraweeHolder.getTopLevelDrawable()); } } 每次為
DraweeView
設置hierarchy
或controller
時,會同時通過super.setImageDrawable(mDraweeHolder.getTopLevelDrawable())
更新需要顯示的圖像。/** * Gets the top-level drawable if hierarchy is set, null otherwise. */ public Drawable getTopLevelDrawable() { return mHierarchy == null ? null : mHierarchy.getTopLevelDrawable(); }
DraweeHierarchy
只定義了一個方法 -getTopLevelDrawable
。public interface DraweeHierarchy { /** * Returns the top level drawable in the corresponding hierarchy. Hierarchy should always have * the same instance of its top level drawable. * @return top level drawable */ public Drawable getTopLevelDrawable(); }
DraweeController
也是一個接口,暴露了設置hierarchy
和接收Event
的方法。void setHierarchy(@Nullable DraweeHierarchy hierarchy)
public boolean onTouchEvent(MotionEvent event)
/** * Interface that represents a Drawee controller used by a DraweeView. *
The view forwards events to the controller. The controller controls * its hierarchy based on those events. */ public interface DraweeController { /** Gets the hierarchy. */ @Nullable public DraweeHierarchy getHierarchy(); /** Sets a new hierarchy. */ void setHierarchy(@Nullable DraweeHierarchy hierarchy); /** * Called when the view containing the hierarchy is attached to a window * (either temporarily or permanently). */ public void onAttach(); /** * Called when the view containing the hierarchy is detached from a window * (either temporarily or permanently). */ public void onDetach(); /** * Called when the view containing the hierarchy receives a touch event. * @return true if the event was handled by the controller, false otherwise */ public boolean onTouchEvent(MotionEvent event); /** * For an animated image, returns an Animatable that lets clients control the animation. * @return animatable, or null if the image is not animated or not loaded yet */ public Animatable getAnimatable(); }
通過以上分析可以看出,
DraweeController
、DraweeHierarchy
、DraweeView
三者共同構成了Fresco
的三駕馬車,下面的博文會各個擊破,分析他們的實現原理和代碼層次。