一鱼响、invalidateSelf()
參考(https://www.zybuluo.com/linux1s1s/note/93075)
我自己也嘗試著看源碼。不過(guò)不同的是在Drawable里面自己調(diào)用invalidateSelf()
,而不是在view里面開(kāi)始筐骇。
1.一個(gè)繼承ImageView
的自定義View
铛纬,重寫(xiě)了setImageDrawble(Drawable drawable)
唬滑。
@Override
public void setImageDrawable(Drawable drawable) {
Tool.LI("WeatherAnimView setImageDrawable");
Drawable d = getDrawable();
if (d != null && d.equals(drawable)) {
return;
}
if (d != null && d instanceof WeatherDrawable) {
((WeatherDrawable) d).stopAnimation();
}
super.setImageDrawable(drawable); // start from here
if (drawable != null && drawable instanceof WeatherDrawable && isShown()) {
((WeatherDrawable) drawable).startAnimation();
}
}
2.從ImageView
的方法setImageDrawable(drawable)
開(kāi)始找View
與Drawable
的關(guān)系
/**
* Sets a drawable as the content of this ImageView.
*
* @param drawable the Drawable to set, or {@code null}
* to clear the content
*/
public void setImageDrawable(@Nullable Drawable drawable) {
if (mDrawable != drawable) {
mResource = 0;
mUri = null;
final int oldWidth = mDrawableWidth;
final int oldHeight = mDrawableHeight;
updateDrawable(drawable);
if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
requestLayout();
}
invalidate();
}
}
3.先從updateDrawable(drawable)
看起。起初被mDrawable
騙了模她,從命名看這是ImageView的成員變量懂牧,updateDrawble(Drawable d)
首先對(duì)其做了一些檢查不管僧凤。接著代碼就很明了,把傳進(jìn)來(lái)的Drawable
對(duì)象賦給成員變量mDrawable
旋膳。如果參數(shù)d
不為空的話(huà)溺忧,那么設(shè)置d的Callback
盯孙。
private void updateDrawable(Drawable d) {
if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) {
mRecycleableBitmapDrawable.setBitmap(null);
}
if (mDrawable != null) {
mDrawable.setCallback(null);//
unscheduleDrawable(mDrawable);
}
mDrawable = d;
if (d != null) {
d.setCallback(this);
d.setLayoutDirection(getLayoutDirection());
if (d.isStateful()) {
d.setState(getDrawableState());
}
d.setVisible(getVisibility() == VISIBLE, true);
d.setLevel(mLevel);
mDrawableWidth = d.getIntrinsicWidth();
mDrawableHeight = d.getIntrinsicHeight();
applyImageTint();
applyColorMod();
configureBounds();
} else {
mDrawableWidth = mDrawableHeight = -1;
}
}
4.繼續(xù)從d.setCallback(this);
看下去振惰,以View
對(duì)象新建一個(gè)弱引用new WeakReference<Callback>(cb)
賦給Drawable
對(duì)象的d
的成員變量mCallback
骑晶。
/**
* Bind a {@link Callback} object to this Drawable. Required for clients
* that want to support animated drawables.
*
* @param cb The client's Callback implementation.
*
* @see #getCallback()
*/public final void setCallback(Callback cb) {
mCallback = new WeakReference<Callback>(cb);
}
正如(https://www.zybuluo.com/linux1s1s/note/93075) 所說(shuō)的草慧,類(lèi)ImageView
的父類(lèi)View
實(shí)現(xiàn)了Drawable.Callback
的接口漫谷。
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
private static final boolean DBG = false;
/**
* The logging tag used by this class with android.util.Log.
*/ protected static final String VIEW_LOG_TAG = "View";
// ...此處省略了余下代碼
查看源碼也可以看到Drawable
類(lèi)定義了該接口
public abstract class Drawable {
// 此處省略了無(wú)關(guān)代碼
private WeakReference<Callback> mCallback = null;// <---- HERE!
// 此間省略了無(wú)關(guān)代碼
/**
* Implement this interface if you want to create an animated drawable that
* extends {@link android.graphics.drawable.Drawable Drawable}.
* Upon retrieving a drawable, use
* {@link Drawable#setCallback(android.graphics.drawable.Drawable.Callback)}
* to supply your implementation of the interface to the drawable; it uses
* this interface to schedule and execute animation changes.
*/public static interface Callback {
// 此處省略了注釋
public void invalidateDrawable(Drawable who);
// 此處省略了注釋
public void scheduleDrawable(Drawable who, Runnable what, long when);
// 此處省略了注釋
public void unscheduleDrawable(Drawable who, Runnable what);
}
Drawable
沒(méi)有實(shí)現(xiàn)任何與用戶(hù)的互動(dòng)碟婆,而完全是交給View
,誠(chéng)如Google文檔(https://developer.android.com/reference/android/graphics/drawable/Drawable.html) 描述的惕稻,View
和Drawable
各司其職。
A Drawable is a general abstraction for "something that can be drawn." Most often you will deal with Drawable as the type of resource retrieved for drawing things to the screen; the Drawable class provides a generic API for dealing with an underlying visual resource that may take a variety of forms. Unlike a View
, a Drawable does not have any facility to receive events or otherwise interact with the user.
二公给、Drawable Call
Google官方文檔描述Drawable
的invalidateSelf()
如下:
invalidateSelf()
Use the current Drawable.Callback
implementation to have this Drawable redrawn.
1.查看Drawable
的invalidateSelf()
源碼如下淌铐。
所以當(dāng)Drawable
內(nèi)部或者其對(duì)象調(diào)用invalidateSelf()
的時(shí)候匣沼,便以Drawable
對(duì)象自身為參數(shù),讓類(lèi)ImageView
來(lái)調(diào)用實(shí)現(xiàn)了Drawable.Callback
的invalidateDrawable(Drawable who)
方法加叁。
/**
* Use the current {@link Callback} implementation to have this Drawable
* redrawn. Does nothing if there is no Callback attached to the
* Drawable.
*
* @see Callback#invalidateDrawable
* @see #getCallback()
* @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public void invalidateSelf() {
final Callback callback = getCallback();
if (callback != null) {
callback.invalidateDrawable(this);
}
}
2.查看View
是如何實(shí)現(xiàn)的invalidateDrawable(Drawable who)
它匕。
如果一切“正辰讶希”扑浸,即參數(shù)dr
等于成員變量mDrawable
且不為空,那么最終會(huì)調(diào)用invalidate()
方法。
@Override
public void invalidateDrawable(Drawable dr) {
if (dr == mDrawable) {
if (dr != null) {
// update cached drawable dimensions if they've changed
final int w = dr.getIntrinsicWidth();
final int h = dr.getIntrinsicHeight();
if (w != mDrawableWidth || h != mDrawableHeight) {
mDrawableWidth = w;
mDrawableHeight = h;
}
}
/* we invalidate the whole view in this case because it's very
* hard to know where the drawable actually is. This is made
* complicated because of the offsets and transformations that
* can be applied. In theory we could get the drawable's bounds
* and run them through the transformation and offsets, but this
* is probably not worth the effort.
*/
invalidate();
} else {
super.invalidateDrawable(dr);
}
}
3.最后invalidate()
可以參考(https://www.zybuluo.com/linux1s1s/note/93075)。