android平台TextView使用ImageSpan展示GIF图片

android-gif-drawable(https://github.com/koral–/android-gif-drawable/releases)开源项目—是一个蛮不错的android gif显示实现.本文在android-gif-drawable基础上介绍如何实现TextView、EditText上展示Gif动态图。

网上有蛮多介绍这个框架使用的文章,比如。

核心类GifDrawable间隔一定时间读取下一帧数据,然后执行invalidateSelf()—-》CallBack::invalidateDrawable()—》View::verifyDrawable()和View::invalidate(),该帧数据刷新流程就执行结束。

而android-gif-drawable框架目前已支持GifImageView、GifImageButton、GifTextView三个android widget,且GifImageView、GifImageButton支持对src和backgroud设置Gif,而GifTextView对支持backgroud和CompoundDrawables设置Gif。

现在很多app都支持Gif表情,但貌似还没有一个app对输入框(等)支持GIF。而基本所有的表情图片(包括Emoji)都是使用ImageSpan实现的。但默认的ImageSpan是无法支持GIF的。

参考android-gif-drawable框架中gif帧数据刷新流程,要支持GIF需要考虑并完成下面三个操作:

1)对ImageSpan中的GifDrawable,何时设置其Callback,又何时清空该Callback,目前TextView、ImageSpan和Spaned都没有设置Callback的地方,我们需要找一个合适的地方将TextView设置为GifDrawable的Callback;

2)在TextView::invalidateDrawable()中实现对GifDrawable的校验,即验证该GifDrawable是TextView的内容,需要刷新;

3)在TextView::invalidateDrawable()中实现如何刷新TextView显示;

首先对于1),我们参考下ImageView和TextView实现。ImageView的src drawable对应实现如下:

/*** Sets a drawable as the content of this ImageView.** @param drawable The drawable to set*/public void setImageDrawable(Drawable drawable) {if (mDrawable != drawable) {…updateDrawable(drawable);…}}private void updateDrawable(Drawable d) {if (mDrawable != null) {mDrawable.setCallback(null);unscheduleDrawable(mDrawable);}mDrawable = d;if (d != null) {d.setCallback(this);if (d.isStateful()) {d.setState(getDrawableState());}d.setLevel(mLevel);d.setLayoutDirection(getLayoutDirection());d.setVisible(getVisibility() == VISIBLE, true);mDrawableWidth = d.getIntrinsicWidth();mDrawableHeight = d.getIntrinsicHeight();applyColorMod();configureBounds();} else {mDrawableWidth = mDrawableHeight = -1;}}也就是说,ImageView在设置其src时,清空旧mDrawable的callback,然后将新设置的src drawable的callback设置为ImageView本身。

同理,TextView对于CompoundDrawables的callback处理也是在setCompoundDrawables()时。

而ImageSpan需要在什么时机设置GifDrawable的callback呢,

public class GifImageSpan extends ImageSpan{private Drawable mDrawable = null;public GifImageSpan(Drawable d) {super(d);mDrawable = d;}public GifImageSpan(Drawable d, int verticalAlignment) {super(d, verticalAlignment);mDrawable = d;}@Overridepublic Drawable getDrawable() {return mDrawable;}}public class GifEditText extends EditText {private GifSpanChangeWatcher mGifSpanChangeWatcher;public GifEditText(Context context) {super(context);initGifSpanChangeWatcher();}public GifEditText(Context context, AttributeSet attrs) {super(context, attrs);initGifSpanChangeWatcher();}public GifEditText(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initGifSpanChangeWatcher();}private void initGifSpanChangeWatcher() {mGifSpanChangeWatcher = new GifSpanChangeWatcher(this);addTextChangedListener(mGifSpanChangeWatcher);}@Overridepublic void setText(CharSequence text, BufferType type) {CharSequence oldText = null;try {//EditText的默认mText为"",是一个String,但getText()强转为Editable,尼玛,只能try/catch了oldText = getText();//首先清空所有旧GifImageSpan的callback和oldText上的GifSpanChangeWatcherif (!TextUtils.isEmpty(oldText) && oldText instanceof Spannable) {Spannable sp = (Spannable) oldText;final GifImageSpan[] spans = sp.getSpans(0, sp.length(), GifImageSpan.class);final int count = spans.length;for (int i = 0; i < count; i++) {spans[i].getDrawable().setCallback(null);}final GifSpanChangeWatcher[] watchers = sp.getSpans(0, sp.length(), GifSpanChangeWatcher.class);final int count1 = watchers.length;for (int i = 0; i < count1; i++) {sp.removeSpan(watchers[i]);}}} catch (Exception e) {}if (!TextUtils.isEmpty(text)) {if (!(text instanceof Editable)) {text = new SpannableStringBuilder(text);}}if (!TextUtils.isEmpty(text) && text instanceof Spannable) {Spannable sp = (Spannable) text;//设置新text中所有GifImageSpan的callback为当前EditTextfinal GifImageSpan[] spans = sp.getSpans(0, sp.length(), GifImageSpan.class);final int count = spans.length;for (int i = 0; i < count; i++) {spans[i].getDrawable().setCallback(this);}//清空新text上的GifSpanChangeWatcherfinal GifSpanChangeWatcher[] watchers = sp.getSpans(0, sp.length(), GifSpanChangeWatcher.class);final int count1 = watchers.length;for (int i = 0; i < count1; i++) {sp.removeSpan(watchers[i]);}if (mGifSpanChangeWatcher == null) {mGifSpanChangeWatcher = new GifSpanChangeWatcher(this);}//设置新text上的GifSpanChangeWatchersp.setSpan(mGifSpanChangeWatcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE | (100 << Spanned.SPAN_PRIORITY_SHIFT));}super.setText(text, type);}}

昨晚多几分钟的准备,今天少几小时的麻烦。

android平台TextView使用ImageSpan展示GIF图片

相关文章:

你感兴趣的文章:

标签云: