我需要替换带有图像的文本短语,然后将其附加到TextView。对于常规Drawables,这没有问题,但是当Drawable是AnimationDrawable时,我不知道何时何地调用.start();
。
这是我将文本追加到TextView的方法:
textview.append(Html.fromHtml(textWithHtmlImgTags, imagegetter, null));
使用imagegetter替换textWithHtmlImgTags中的图像标记:
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帧上)。
在文档中说:
重要的是要注意,在Activity的onCreate()方法中,无法调用在AnimationDrawable上调用的start()方法,因为AnimationDrawable尚未完全附加到窗口。如果你想立即播放动画而不需要交互,那么你可能想从你的Activity中的onWindowFocusChanged()方法调用它,当Android让你的窗口成为焦点时会调用它。
由于图像是动态添加的,我认为它与onCreate()没有任何关系。
所以我想在我的可绘制.start()
时调用我的is not yet fully attached to the window
,但是在哪里/何时/如何 我称之为?
提前致谢!
答案 0 :(得分: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);
}
}
答案 1 :(得分:1)
我想重要的问题是:你什么时候打电话?
textview.append(Html.fromHtml(textWithHtmlImgTags...
如果你在onCreate之后调用它,那么你可以调用animation.start()。如果在onCreate()方法中调用它,我会:
答案 2 :(得分:1)
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使其缓存的显示列表无效,否则不会绘制更新的帧。
我还发现由于某种原因,如果我创建了ImageSpan,引用了动画资源id,则资源不会被缓存,并且每次调用ImageSpan.getDrawable()时都会重新加载。通过加载资源,设置其边界,并将其传递给ImageSpan构造函数,我避免了这个问题。
使用onAttachedToWindow / onDetachedFromWindow,否则建议使用。