2012-02-23 94 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,否则建议。