gpt4 book ai didi

android - Android中TextView或EditText中如何添加动画表情

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:50:33 24 4
gpt4 key购买 nike

作为问题,我使用 ImageSpan 将图像添加到 TextView 中。但它不能动画。你有什么建议吗?
我尝试扩展 AnimationDrawable 以将可绘制对象添加到 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();
}
}

最佳答案

我会尝试:

  • 将动画图像(大概是 .gif 文件?)拆分为单独的帧并将它们组合成 AnimationDrawable然后将其传递给 ImageSpan 的构造函数。
  • 继承 ImageSpan 并覆盖 onDraw() 方法以添加您自己的逻辑以根据某种计时器绘制不同的帧。有一个 api 演示说明了如何使用 Movie 类加载可能值得研究的动画 gif。

大编辑:好吧,很抱歉没有早点回来,但我不得不留出一些时间自己调查一下。我玩过它,因为我 future 的一个项目可能需要一个解决方案。不幸的是,我在使用 AnimationDrawable 时遇到了类似的问题,这似乎是由 DynamicDrawableSpan(ImageSpan 的间接父类(super class))的缓存机制引起的) 用途。

对我来说,另一个问题是似乎没有直接的办法使 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();
}

}

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();

}

}

用法:

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

如您所见,我使用了一个处理程序来提供“滴答声”以前进到下一帧。这样做的好处是它只会在应该渲染新帧时触发更新。实际的重绘是通过使包含 AnimatedImageSpan 的 TextView 无效来完成的。同时,缺点是每当您在同一个 TextView(或多个)中有一堆动画 gif 时, View 可能会疯狂更新……请明智地使用它。 :)

关于android - Android中TextView或EditText中如何添加动画表情,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8632801/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com