在TextView中dynamic加载AnimationDrawable

我需要用图像replace文本中的短语,然后将其附加到TextView。 对于常规的Drawables来说,这没有问题,但是当Drawable是一个AnimationDrawable时,我不知道何时何地调用.start();

这是我如何将文本追加到TextView:

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

textWithHtmlImgTags中的图像标签被imagegetterreplace:

 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被添加,但他们没有animation(他们卡在第1帧)。

在文档中说:

注意在AnimationDrawable上调用的start()方法不能在Activity的onCreate()方法中调用,因为AnimationDrawable尚未完全附加到窗口。 如果您想要立即播放animation,而不需要交互,那么您可能需要从Activity中的onWindowFocusChanged()方法调用该方法,这会在Android将窗口放到焦点上时调用。

由于图像是dynamic添加的,我不认为它与onCreate()有任何关系。 所以我想我打电话给我的.start()时,我的drawable is not yet fully attached to the window ,但在哪里/何时/我应该怎样称呼它?

提前致谢!

Solutions Collecting From Web of "在TextView中dynamic加载AnimationDrawable"

我拿出了解决scheme。 在你的自定义TextView中:

(1)首先,你必须决定animation开始和停止的时间。

 @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); } } 

我想重要的问题是:你什么时候打电话?

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

如果你在onCreate之后调用这个,那么你可以调用animation.start()。 如果在onCreate()方法中调用它,我会:

  • 保留在ImageGetter中生成的可绘制的列表;
  • 在onAttachedToWindow或onStart中的所有drawable上调用start()(不知道它们是否在onStart函数中工作)

View已经实现了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.Callback的超类实现将接受意外的Drawable对象并处理调度。

调用onLayout强制TextView使其caching的显示列表失效,否则不会绘制更新的帧。

我还发现,由于某种原因,如果我创build了引用animation资源ID的ImageSpan,则资源没有被caching,并且每次调用ImageSpan.getDrawable()时都会重新加载资源。 通过加载资源,设置边界,并将其传递给ImageSpan构造函数,我避免了这个问题。

另外build议使用onAttachedToWindow / onDetachedFromWindow。