Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/234.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在TextView或Android中的EditText中添加动画表情_Android_Gif - Fatal编程技术网

如何在TextView或Android中的EditText中添加动画表情

如何在TextView或Android中的EditText中添加动画表情,android,gif,Android,Gif,问题是,我使用ImageSpan将图像添加到TextView中。但是它不能动。你有什么建议吗? 我尝试扩展AnimationDrawable,将drawable添加到ImageSpan中。但它不起作用 public class EmoticonDrawalbe extends AnimationDrawable { private Bitmap bitmap; private GifDecode decode; private int gifCount; pub

问题是,我使用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();
    }
}
public类EmoticonDrawalbe扩展了AnimationDrawable{
私有位图;
专用gif解码;
私人积分计数;
公共EmoticonDrawalbe(上下文,字符串源){
decode=新的GifDecode();
解码。读取(上下文、源);
gifCount=decode.getFrameCount();

如果(gifCount,则可以使用ObjectAnimator在ImageSpan中为可绘制对象设置动画

我会尝试:

  • 将动画图像(可能是一个.gif文件?)拆分为单独的帧,并将这些帧组合成一个新的帧,然后传递给ImageSpan的构造函数
  • 子类ImageSpan并重写
    onDraw()
    方法,添加您自己的逻辑,根据某种计时器绘制不同的帧。有一个api演示,演示了如何使用Movie类加载动画gif,这可能值得一看
大编辑: 好的,很抱歉没有早点回来,但我不得不留出一些时间自己调查这件事。我已经玩过了,因为我自己可能需要一个解决方案来解决我未来的一个项目。不幸的是,我在使用
AnimationDrawable
时遇到了类似的问题,这似乎是由缓存
DynamicDrawableSpan
(图像span
的一个间接超类)使用的机制

对我来说,另一个问题是,似乎没有一个简单的wat来使可绘图文件或ImageSpan无效。可绘图文件实际上有
invalidateDrawable(可绘图)
invalidateSelf()
方法,但第一种方法在我的情况下没有任何效果,而后一种方法只有在附加了一些神奇的
Drawable.Callback
时才有效。我找不到任何关于如何使用此方法的正式文档

因此,我在逻辑树上进一步解决了这个问题。我必须提前添加一个警告,这很可能不是一个最佳解决方案,但目前这是我唯一能够使用的解决方案。如果你偶尔使用我的解决方案,你可能不会遇到问题,但我会尽量避免在整个屏幕上填充表情符号我不确定会发生什么,但话说回来,我甚至都不想知道

不用多说,下面是代码。我添加了一些注释以使其不言自明。它很可能使用了不同的Gif解码类/库,但应该可以与任何其他类/库一起使用

animatedgiftrawable.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();
    }

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

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

很酷,我以前没有注意到这个类。看起来很有趣,虽然它只支持启动API Level 11.tks。请您提供一个示例,我会试试。谢谢!tks您的建议,我会试试。很抱歉,我一定是暂时的大脑崩溃。我想写“”.我也在我的答案中更正了它。我也修复了我的问题,你可能会看到我扩展了AnimationDrawable,但它不起作用。.好的,我自己花了一些时间来处理这个问题。请在我更新的答案中找到结果-希望有帮助!什么是Gif解码类/库?你能分享链接吗