I would try either:
- Separate the animated image (presumably a .gif? File) into separate frames and combine them into an AnimationDrawable , then go to the ImageSpan constructor.
- Subclass ImageSpan and override the
onDraw() method to add your own logic to draw different frames based on some kind of timer. There's a demo version of the api that illustrates how to use the Movie class to load an animated gif, which might be worth a look.
Big change: Okay, sorry I didn't come back earlier, but I had to set aside some time to research it myself. I had a game with him, as I will probably need a solution for this for one of my future projects. Unfortunately, I ran into similar issues using AnimationDrawable , which seems to be caused by a caching mechanism that uses DynamicDrawableSpan (an indirect superclass from ImageSpan ).
Another problem for me is that there seems to be no direct access to the invalidity of Drawable or ImageSpan. Actually Drawable has invalidateDrawable(Drawable) and invalidateSelf() methods, but the former had no effect in my case, while the latter only works if the magic Drawable.Callback attached. I could not find decent documentation on how to use this ...
So, I went further through the logical tree to solve the problem. I must add a warning in advance that this is most likely not the best solution, but at the moment it is the only one I could work with. You probably will not run into problems if you use your solution sporadically, but I would not fill the entire screen with emoticons. I'm not sure what will happen, but then again, I probably don't even want to know.
No noise, here is the code. I added a few comments to make it clear. He probably used a different Gif / libary decoding class, but he should work with any of them.
AnimatedGifDrawable.java
public class AnimatedGifDrawable extends AnimationDrawable { private int mCurrentIndex = 0; private UpdateListener mListener; public AnimatedGifDrawable(InputStream source, UpdateListener listener) { mListener = listener; GifDecoder decoder = new GifDecoder(); decoder.read(source);
AnimatedImageSpan.java
public class AnimatedImageSpan extends DynamicDrawableSpan { private Drawable mDrawable; public AnimatedImageSpan(Drawable d) { super(); mDrawable = d;
Application:
final TextView gifTextView = (TextView) findViewById(R.id.gif_textview); SpannableStringBuilder sb = new SpannableStringBuilder(); sb.append("Text followed by animated gif: "); String dummyText = "dummy"; sb.append(dummyText); sb.setSpan(new AnimatedImageSpan(new AnimatedGifDrawable(getAssets().open("agif.gif"), new AnimatedGifDrawable.UpdateListener() { @Override public void update() { gifTextView.postInvalidate(); } })), sb.length() - dummyText.length(), sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); gifTextView.setText(sb);
As you can see, I used a handler to provide βticksβ for moving to the next frame. The advantage of this is that it will only disable the update whenever a new frame needs to be rendered. Actual redrawing is done by invalidating the TextView that contains the AnimatedImageSpan. At the same time, the disadvantage is that whenever you have a bunch of animated gifs in the same TextView (or a few, for that matter), the views can be updated as crazy ... Use it wisely. :)