2012-02-23 33 views
8

我需要用圖像替換文本中的短語,然後將其附加到TextView。對於普通Drawables來說這沒有問題,但是當Drawable是一個AnimationDrawable時,我不知道何時何地調用.start();動態加載TextView中的AnimationDrawable

這是我如何添加文字的TextView:

textview.append(Html.fromHtml(textWithHtmlImgTags, imagegetter, null)); 

在textWithHtmlImgTags圖片代碼使用imagegetter代替:

new ImageGetter() 
{ 
    @Override 
    public Drawable getDrawable(String source) { 

     if(source.endsWith("_ani")) 
     { 
      Log.i("cmv", "This is an animated drawable."); 

      AnimationDrawable dra = (AnimationDrawable)res.getDrawable(sRes.get(source)); 
      dra.setBounds(0, 0, dra.getIntrinsicWidth(), dra.getIntrinsicHeight()); 
      dra.start(); // This doesn't work.. 

      return dra; 
     } 

     Drawable dr = res.getDrawable(sRes.get(source)); 
     dr.setBounds(0, 0, dr.getIntrinsicWidth(), dr.getIntrinsicHeight()); 
     return dr; 
    } 

}; 

我AnimationDrawables添加,但它們不是動畫(他們卡在第1幀)。

在本文檔中,它說:

需要注意的是不能將活動的onCreate()方法中調用呼籲AnimationDrawable的start()方法是很重要的,因爲AnimationDrawable尚未完全附在窗戶上。如果您想要立即播放動畫而不需要交互,那麼您可能需要從Activity中的onWindowFocusChanged()方法調用該動畫,這會在Android將窗口放到焦點上時調用。

由於圖像是動態添加的,我不認爲它與onCreate()有任何關係。 所以我想我打電話給我.start()當我的可繪製的is not yet fully attached to the window,但何時/何時/如何應該我稱之爲?

在此先感謝!

+0

設置drawbales之後調用'textView.bringToFront()',然後調用'.start()'使其生成動畫.. – MKJParekh 2012-04-16 12:09:46

回答

6

我想出瞭解決方案。 在您的自定義TextView中:

(1)首先,您必須決定動畫開始和停止的時間。

@Override 
protected void onAttachedToWindow() { 
    super.onAttachedToWindow(); 

    handleAnimationDrawable(true); 
} 

@Override 
protected void onDetachedFromWindow() { 
    super.onDetachedFromWindow(); 

    handleAnimationDrawable(false); 
} 

private void handleAnimationDrawable(boolean isPlay) { 
    CharSequence text = getText(); 
    if (text instanceof Spanned) { 
     Spanned span = (Spanned) text; 
     ImageSpan[] spans = span.getSpans(0, span.length() - 1, 
       ImageSpan.class); 
     for (ImageSpan s : spans) { 
      Drawable d = s.getDrawable(); 
      if (d instanceof AnimationDrawable) { 
       AnimationDrawable animationDrawable = (AnimationDrawable) d; 
       if (isPlay) { 
        animationDrawable.setCallback(this); 
        animationDrawable.start(); 
       } else { 
        animationDrawable.stop(); 
        animationDrawable.setCallback(null); 
       } 
      } 
     } 
    } 
} 

(2)然後實現自己的Drawable.Callback來觸發重繪。

@Override 
public void invalidateDrawable(Drawable dr) { 
    invalidate(); 
} 

@Override 
public void scheduleDrawable(Drawable who, Runnable what, long when) { 
    if (who != null && what != null) { 
     mHandler.postAtTime(what, when); 
    } 
} 

@Override 
public void unscheduleDrawable(Drawable who, Runnable what) { 
    if (who != null && what != null) { 
     mHandler.removeCallbacks(what); 
    } 
} 
+0

太棒了!這正是我需要的! – 2012-04-30 00:27:18

1

我想重要的問題是:你什麼時候打電話?

textview.append(Html.fromHtml(textWithHtmlImgTags... 

如果您在onCreate之後調用此函數,那麼您可以調用animation.start()。如果在onCreate()方法中調用它,我會:

  • 保留在ImageGetter中生成的可繪製列表;
  • 調用start()所有在onAttachedToWindow或在onStart的可繪製(不知道他們是否在調用onStart函數工作)的
+0

我多次撥打電話,第一個電話在onCreate中。之後,它被稱爲多次(每當應用程序從服務器獲得響應時)。我試着保留所有AnimationDrawables的列表,並在AttachedToWindow上啓動它們,但它們仍然停留在第一幀。 – 2012-04-29 19:37:38

1

查看已經實現Drawable.Callback所以你只需要下面的TextView覆蓋在ImageSpan顯示AnimationDrawable對象:

// comparing against drawables found in the spans is probably safer 
@Override 
protected boolean verifyDrawable(Drawable who) { 
    return (super.verifyDrawable(who) || who instanceof AnimationDrawable); 
} 

// again comparing against drawables found in the spans is probably safer 
@Override 
public void invalidateDrawable(Drawable drawable) { 
    if (drawable instanceof AnimationDrawable) { 
     onLayout(true, getLeft(), getTop(), getRight(), getBottom()); 
     invalidate(); 
     return; 
    } 
    super.invalidateDrawable(drawable); 
} 

重載verifyDrawable是必要的,這樣可繪製的超類實現。回調將接受意外的Drawable對象並處理調度。

調用onLayout強制TextView使其緩存的顯示列表失效,否則不會繪製更新的幀。

我還發現,由於某種原因,如果我創建引用動畫資源ID的ImageSpan,則資源沒有被緩存,並且每次調用ImageSpan.getDrawable()時都會重新加載資源。通過加載資源,設置邊界,並將其傳遞給ImageSpan構造函數,我避免了這個問題。

使用onAttachedToWindow/onDetachedFromWindow,否則建議。