一、invalidateSelf()
参考(https://www.zybuluo.com/linux1s1s/note/93075)
我自己也尝试着看源码。不过不同的是在Drawable里面自己调用invalidateSelf()
,而不是在view里面开始。
1.一个继承ImageView
的自定义View
,重写了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)
开始找View
与Drawable
的关系
/**
* 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)
首先对其做了一些检查不管。接着代码就很明了,把传进来的Drawable
对象赋给成员变量mDrawable
。如果参数d
不为空的话,那么设置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.继续从d.setCallback(this);
看下去,以View
对象新建一个弱引用new WeakReference<Callback>(cb)
赋给Drawable
对象的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) 所说的,类ImageView
的父类View
实现了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
类定义了该接口
public abstract class Drawable {
// 此处省略了无关代码
private WeakReference<Callback> mCallback = null;// <---- HERE!
// 此间省略了无关代码
/**
* 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
没有实现任何与用户的互动,而完全是交给View
,诚如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()
源码如下。
所以当Drawable
内部或者其对象调用invalidateSelf()
的时候,便以Drawable
对象自身为参数,让类ImageView
来调用实现了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
是如何实现的invalidateDrawable(Drawable who)
。
如果一切“正常”,即参数dr
等于成员变量mDrawable
且不为空,那么最终会调用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)。
网友评论