/** * 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自己。
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; } @Override public 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); } @Override public void setText(CharSequence text, BufferType type) { CharSequence oldText = null; try { //EditText的默認mText爲""。是一個String。但getText()強轉爲Editable,尼瑪。僅僅能try/catch了 oldText = getText(); //首先清空所有舊GifImageSpan的callback和oldText上的GifSpanChangeWatcher if (!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爲當前EditText 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(this); } //清空新text上的GifSpanChangeWatcher 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]); } if (mGifSpanChangeWatcher == null) { mGifSpanChangeWatcher = new GifSpanChangeWatcher(this); } //設置新text上的GifSpanChangeWatcher sp.setSpan(mGifSpanChangeWatcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE | (100 << Spanned.SPAN_PRIORITY_SHIFT)); } super.setText(text, type); } }
public class GifSpanChangeWatcher implements SpanWatcher, TextWatcher{ private Drawable.Callback mCallback; public GifSpanChangeWatcher(Drawable.Callback callback) { mCallback = callback; } public void onSpanChanged(Spannable buf, Object what, int s, int e, int st, int en) { //do nothing } public void onSpanAdded(Spannable buf, Object what, int s, int e) { //設置callback if (what instanceof GifImageSpan) { ((GifImageSpan)what).getDrawable().setCallback(mCallback); } } public void onSpanRemoved(Spannable buf, Object what, int s, int e) { //清空callback if (what instanceof GifImageSpan) { ((GifImageSpan)what).getDrawable().setCallback(null); } } @Override public void afterTextChanged(Editable s) { if (s != null) { s.setSpan(this, 0, s.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE | (100 << Spanned.SPAN_PRIORITY_SHIFT)); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // TODO Auto-generated method stub } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // TODO Auto-generated method stub } }
@Override protected boolean verifyDrawable(Drawable dr) { return mDrawable == dr || super.verifyDrawable(dr); }
@Override protected boolean verifyDrawable(Drawable who) { final boolean verified = super.verifyDrawable(who); if (!verified && mDrawables != null) { return who == mDrawables.mDrawableLeft || who == mDrawables.mDrawableTop || who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom || who == mDrawables.mDrawableStart || who == mDrawables.mDrawableEnd; } return verified; }直接上代碼
public class GifEditText extends EditText { private GifImageSpan getImageSpan(Drawable drawable) { GifImageSpan imageSpan = null; CharSequence text = getText(); if (!TextUtils.isEmpty(text)) { if (text instanceof Spanned) { Spanned spanned = (Spanned) text; GifImageSpan[] spans = spanned.getSpans(0, text.length(), GifImageSpan.class); if (spans != null && spans.length > 0) { for (GifImageSpan span : spans) { if (drawable == span.getDrawable()) { imageSpan = span; } } } } } return imageSpan; } }getImageSpan()方法經過getSpans()獲取所有的GifImageSpan。而後對照drawable,返回對應的GifImageSpan。
@Override public void invalidateDrawable(Drawable drawable) { if (verifyDrawable(drawable)) { final Rect dirty = drawable.getBounds(); int scrollX = mScrollX; int scrollY = mScrollY; // IMPORTANT: The coordinates below are based on the coordinates computed // for each compound drawable in onDraw(). Make sure to update each section // accordingly. final TextView.Drawables drawables = mDrawables; if (drawables != null) { if (drawable == drawables.mDrawableLeft) { final int compoundPaddingTop = getCompoundPaddingTop(); final int compoundPaddingBottom = getCompoundPaddingBottom(); final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop; scrollX += mPaddingLeft; scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightLeft) / 2; } else if (drawable == drawables.mDrawableRight) { final int compoundPaddingTop = getCompoundPaddingTop(); final int compoundPaddingBottom = getCompoundPaddingBottom(); final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop; scrollX += (mRight - mLeft - mPaddingRight - drawables.mDrawableSizeRight); scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightRight) / 2; } else if (drawable == drawables.mDrawableTop) { final int compoundPaddingLeft = getCompoundPaddingLeft(); final int compoundPaddingRight = getCompoundPaddingRight(); final int hspace = mRight - mLeft - compoundPaddingRight - compoundPaddingLeft; scrollX += compoundPaddingLeft + (hspace - drawables.mDrawableWidthTop) / 2; scrollY += mPaddingTop; } else if (drawable == drawables.mDrawableBottom) { final int compoundPaddingLeft = getCompoundPaddingLeft(); final int compoundPaddingRight = getCompoundPaddingRight(); final int hspace = mRight - mLeft - compoundPaddingRight - compoundPaddingLeft; scrollX += compoundPaddingLeft + (hspace - drawables.mDrawableWidthBottom) / 2; scrollY += (mBottom - mTop - mPaddingBottom - drawables.mDrawableSizeBottom); } } invalidate(dirty.left + scrollX, dirty.top + scrollY, dirty.right + scrollX, dirty.bottom + scrollY); } }計算compoundDrawable位置欄,而後運行invalidate。
對於GifEditText貌似也可以相似操做,依據GifImageSpan的start、end計算其位置欄,而後運行invalidate()。只是計算過程太過複雜了。只是android4.4的TextView提供這種方法void invalidateRegion(int start, int end, boolean invalidateCursor) 方法用於刷新start和end之間的區域,但仍是蠻複雜的看的人眼花繚亂。研究了下這種方法終因而由誰調用的。html
@Override public void invalidateDrawable(Drawable drawable) { GifImageSpan imageSpan = getImageSpan(drawable); Log.e("", "invalidateDrawable imageSpan:" + imageSpan); if (imageSpan != null) { CharSequence text = getText(); if (!TextUtils.isEmpty(text)) { if (text instanceof Editable) { Log.e("", "invalidateDrawable Editable:"); Editable editable = (Editable)text; int start = editable.getSpanStart(imageSpan); int end = editable.getSpanEnd(imageSpan); int flags = editable.getSpanFlags(imageSpan); editable.setSpan(imageSpan, start, end, flags); } } } else { super.invalidateDrawable(drawable); } }直接又一次設置該ImageSpan就能夠觸發ChangeWatcher::onSpanChanged()回調。也就會立刻刷新其區域和cursor。
public class GifSpanTextView extends GifTextView { private GifSpanChangeWatcher mGifSpanChangeWatcher; public GifSpanTextView(Context context) { super(context); initGifSpanChangeWatcher(); } public GifSpanTextView(Context context, AttributeSet attrs) { super(context, attrs); initGifSpanChangeWatcher(); } public GifSpanTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initGifSpanChangeWatcher(); } private void initGifSpanChangeWatcher() { mGifSpanChangeWatcher = new GifSpanChangeWatcher(this); addTextChangedListener(mGifSpanChangeWatcher); } @Override public void setText(CharSequence text, BufferType type) { type = BufferType.EDITABLE; CharSequence oldText = getText(); if (!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]); } } if (!TextUtils.isEmpty(text) && text instanceof Spannable) { Spannable sp = (Spannable) text; 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(this); } 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]); } if (mGifSpanChangeWatcher == null) { mGifSpanChangeWatcher = new GifSpanChangeWatcher(this);; } sp.setSpan(mGifSpanChangeWatcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE | (100 << Spanned.SPAN_PRIORITY_SHIFT)); } super.setText(text, type); } private GifImageSpan getImageSpan(Drawable drawable) { GifImageSpan imageSpan = null; CharSequence text = getText(); if (!TextUtils.isEmpty(text)) { if (text instanceof Spanned) { Spanned spanned = (Spanned) text; GifImageSpan[] spans = spanned.getSpans(0, text.length(), GifImageSpan.class); if (spans != null && spans.length > 0) { for (GifImageSpan span : spans) { if (drawable == span.getDrawable()) { imageSpan = span; } } } } } return imageSpan; } @Override public void invalidateDrawable(Drawable drawable) { GifImageSpan imageSpan = getImageSpan(drawable); if (imageSpan != null) { CharSequence text = getText(); if (!TextUtils.isEmpty(text)) { if (text instanceof Editable) { Editable editable = (Editable)text; int start = editable.getSpanStart(imageSpan); int end = editable.getSpanEnd(imageSpan); int flags = editable.getSpanFlags(imageSpan); editable.removeSpan(imageSpan); editable.setSpan(imageSpan, start, end, flags); } } } else { super.invalidateDrawable(drawable); } } }
設置其android:editable="true"或正上方setText(CharSequence text, BufferType type)將type設置BufferType.EDITABLE。java