作为问题,我使用ImageSpan将图像添加到TextView中.但是它不能
动画.你有任何建议吗?我尝试扩展AnimationDrawable以将drawable添加到ImageSpan中.但它不起作用
public class EmoticonDrawalbe extends AnimationDrawable {
private Bitmap bitmap;
private GifDecode decode;
private int gifCount;
public EmoticonDrawalbe(Context context, String source) {
decode = new GifDecode();
decode.read(context, source);
gifCount = decode.getFrameCount();
if (gifCount <= 0) {
return;
}
for (int i = 0; i < gifCount; i++) {
bitmap = decode.getFrame(i);
addFrame(new BitmapDrawable(bitmap), decode.getDelay(i));
}
setOneShot(false);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
start();
}
}
Run Code Online (Sandbox Code Playgroud)
MH.*_*MH. 22
我会尝试:
onDraw()方法以添加您自己的逻辑,以根据某种计时器绘制不同的帧.有一个api演示,演示如何使用Movie类加载可能值得研究的动画gif.Big Edit:
好的,抱歉没有早点回来,但我不得不留出一些时间来自己调查.我玩过它,因为我可能需要一个解决方案,我自己的未来项目之一.不幸的是,我遇到了使用a的类似问题AnimationDrawable,这似乎是由DynamicDrawableSpan(间接超类ImageSpan)使用的缓存机制引起的.
对我来说另一个问题是,似乎没有一个简单的使用无效的Drawable或ImageSpan.Drawable实际上有invalidateDrawable(Drawable)和invalidateSelf()方法,但第一个在我的情况下没有任何影响,而后者只有Drawable.Callback在附加一些魔法时才有效.我找不到任何关于如何使用这个的体面文件......
所以,我更进一步向上逻辑树来解决问题.我必须事先添加一个警告,这很可能不是最佳解决方案,但现在它是我唯一可以上班的.如果你偶尔使用我的解决方案,你可能不会遇到问题,但我会避免用表情符号填满整个屏幕.我不确定会发生什么,但话说回来,我可能甚至都不想知道.
不用多说,这是代码.我添加了一些评论,使其不言自明.它很可能是一个使用不同的Gif解码类/库,但它应该适用于任何在那里.
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);
// Iterate through the gif frames, add each as animation frame
for (int i = 0; i < decoder.getFrameCount(); i++) {
Bitmap bitmap = decoder.getFrame(i);
BitmapDrawable drawable = new BitmapDrawable(bitmap);
// Explicitly set the bounds in order for the frames to display
drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
addFrame(drawable, decoder.getDelay(i));
if (i == 0) {
// Also set the bounds for this container drawable
setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
}
}
}
/**
* Naive method to proceed to next frame. Also notifies listener.
*/
public void nextFrame() {
mCurrentIndex = (mCurrentIndex + 1) % getNumberOfFrames();
if (mListener != null) mListener.update();
}
/**
* Return display duration for current frame
*/
public int getFrameDuration() {
return getDuration(mCurrentIndex);
}
/**
* Return drawable for current frame
*/
public Drawable getDrawable() {
return getFrame(mCurrentIndex);
}
/**
* Interface to notify listener to update/redraw
* Can't figure out how to invalidate the drawable (or span in which it sits) itself to force redraw
*/
public interface UpdateListener {
void update();
}
}
Run Code Online (Sandbox Code Playgroud)
AnimatedImageSpan.java
public class AnimatedImageSpan extends DynamicDrawableSpan {
private Drawable mDrawable;
public AnimatedImageSpan(Drawable d) {
super();
mDrawable = d;
// Use handler for 'ticks' to proceed to next frame
final Handler mHandler = new Handler();
mHandler.post(new Runnable() {
public void run() {
((AnimatedGifDrawable)mDrawable).nextFrame();
// Set next with a delay depending on the duration for this frame
mHandler.postDelayed(this, ((AnimatedGifDrawable)mDrawable).getFrameDuration());
}
});
}
/*
* Return current frame from animated drawable. Also acts as replacement for super.getCachedDrawable(),
* since we can't cache the 'image' of an animated image.
*/
@Override
public Drawable getDrawable() {
return ((AnimatedGifDrawable)mDrawable).getDrawable();
}
/*
* Copy-paste of super.getSize(...) but use getDrawable() to get the image/frame to calculate the size,
* in stead of the cached drawable.
*/
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
Drawable d = getDrawable();
Rect rect = d.getBounds();
if (fm != null) {
fm.ascent = -rect.bottom;
fm.descent = 0;
fm.top = fm.ascent;
fm.bottom = 0;
}
return rect.right;
}
/*
* Copy-paste of super.draw(...) but use getDrawable() to get the image/frame to draw, in stead of
* the cached drawable.
*/
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
Drawable b = getDrawable();
canvas.save();
int transY = bottom - b.getBounds().bottom;
if (mVerticalAlignment == ALIGN_BASELINE) {
transY -= paint.getFontMetricsInt().descent;
}
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
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);
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我使用Handler来提供"ticks"以前进到下一帧.这样做的好处是,只有在应该渲染新帧时,它才会触发更新.实际的重绘是通过使包含AnimatedImageSpan的TextView无效来完成的.与此同时,缺点是每当你在同一个TextView中有一堆GIF动画(或者就此而言是多个)时,视图可能会像疯了一样更新......明智地使用它.:)
您可以使用 ObjectAnimator 对 ImageSpan 中的可绘制对象进行动画处理
http://developer.android.com/reference/android/animation/ObjectAnimator.html
| 归档时间: |
|
| 查看次数: |
9307 次 |
| 最近记录: |