鍍金池/ 教程/ Android/ 自定義View
進(jìn)度條
在JAVA代碼中使用Drawees
Drawee的各種效果配置
緩存
一些陷阱
關(guān)于在Android Studio中編譯
多圖請求及圖片復(fù)用
自定義網(wǎng)絡(luò)加載
支持的URIs
可關(guān)閉的引用
監(jiān)聽下載事件
修改圖片
引入Fresco
縮放
圓角和圓圈
配置Image Pipeline
縮放和旋轉(zhuǎn)圖片
(圖片請求)Image Requests
自定義View
使用ControllerBuilder
在XML中使用Drawees
開始使用 Fresco
關(guān)鍵概念
Image Pipeline介紹
漸進(jìn)式JPEG圖
數(shù)據(jù)源和數(shù)據(jù)訂閱者
直接使用Image Pipeline
動畫圖(gif)
使用其他的Image Loader

自定義View

本教程內(nèi)容來源于:http://fresco-cn.org
采用 知識共享 署名 4.0 國際 許可協(xié)議 進(jìn)行許可

DraweeHolders

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

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

  • DraweeHolder 單圖情況下用。
  • MultiDraweeHolder 多圖情況下用。

自定義View需要完成的事情

Android 呈現(xiàn)View對象,只有View對象才能得到一些系統(tǒng)事件的通知。DraweeViews 處理這些事件通知,高效地管理內(nèi)存。使用DraweeHolder時,你需要自己實(shí)現(xiàn)這幾個方法。

處理 attach/detach 事件

如果沒按照以下步驟實(shí)現(xiàn)的話,很可能會引起內(nèi)存泄露

當(dāng)圖片不再在View上顯示時,比如滑動時View滑動到屏幕外,或者不再繪制,圖片就不應(yīng)該再存在在內(nèi)存中。Drawees 監(jiān)聽這些事情,并負(fù)責(zé)釋放內(nèi)存。當(dāng)圖片又需要顯示時,重新加載。

這些在DraweeView中是自動的,但是在自定義View中,需要我們自己去操作,如下:

DraweeHolder mDraweeHolder;

@Override
public void onDetachedFromWindow() {
  super.onDetachedToWindow();
  mDraweeHolder.onDetach();
}

@Override
public void onStartTemporaryDetach() {
  super.onStartTemporaryDetach();
  mDraweeHolder.onDetach();
}

@Override
public void onAttachedToWindow() {
  super.onAttachedToWindow();
  mDraweeHolder.onAttach();
}

@Override
public void onFinishTemporaryDetach() {
  super.onFinishTemporaryDetach();
  mDraweeHolder.onAttach();
}

處理觸摸事件

如果你啟用了點(diǎn)擊重新加載,在自定義View中,需要這樣:

@Override
public boolean onTouchEvent(MotionEvent event) {
  return mDraweeHolder.onTouchEvent(event) || super.onTouchEvent(event);
}

自定義onDraw

Drawable drawable = mDraweeHolder.getHierarchy().getTopLevelDrawable();
drawable.setBounds(...);

否則圖片將不會出現(xiàn)

  • 不要向下轉(zhuǎn)換這個Drawable
  • 不要變換這個Drawable

其他應(yīng)該做的

  • 重寫 verifyDrawable:
@Override
protected boolean verifyDrawable(Drawable who) {
  if (who == mDraweeHolder.getHierarchy().getTopLevelDrawable()) {
    return true;
  }
  // 對其他Drawable的驗(yàn)證邏輯
}
  • 確保invalidateDrawable 處理了圖片占用的那塊區(qū)域。

創(chuàng)建 DraweeHolder

這同樣需要非常小心和細(xì)致

構(gòu)造函數(shù)

我們推薦如下實(shí)現(xiàn)構(gòu)造函數(shù):

  • 重寫3個構(gòu)造函數(shù)
  • 在每個構(gòu)造函數(shù)中調(diào)用同等簽名的父類構(gòu)造函數(shù),和一個私有的init方法。
  • init方法中執(zhí)行初始化操作。

即,不要在構(gòu)造函數(shù)中用this來調(diào)用另外一個構(gòu)造。

這樣可以保證,不管調(diào)用哪個構(gòu)造,都可以正確地執(zhí)行初始化流程。然后在init方法中創(chuàng)建holder。

創(chuàng)建 Holder

如果有可能,只在View創(chuàng)建時,創(chuàng)建Drawees。創(chuàng)建DraweeHierarchy開銷較大,最好只做一次。

class CustomView extends View {
  DraweeHolder<GenericDraweeHierarchy> mDraweeHolder;

  // constructors following above pattern

  private void init() {
    GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(getResources());
      .set...
      .set...
      .build();
    mDraweeHolder = DraweeHolder.create(hierarchy, context);
  }
}

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

使用controller builder創(chuàng)建DraweeController,然后調(diào)用holder的setController方法,而不是設(shè)置給自定義View。

DraweeController controller = Fresco.newControllerBuilder()
    .setUri(uri)
    .setOldController(mDraweeHolder.getController())
    .build();
mDraweeHolder.setController(controller);

MultiDraweeHolder

DraweeHolder相比,MultiDraweeHolderadd, remove, clear 等方法可以操作Drawees。如下:

MultiDraweeHolder<GenericDraweeHierarchy> mMultiDraweeHolder;

private void init() {
  GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(getResources());
    .set...
    .build();
  mMultiDraweeHolder = new MultiDraweeHolder<GenericDraweeHierarchy>();
  mMultiDraweeHolder.add(new DraweeHolder<GenericDraweeHierarchy>(hierarchy, context));
  // repeat for more hierarchies
}

同樣,也需要處理系統(tǒng)事件,設(shè)置聲音等等,就想處理單個DraweeHolder那樣。