美文网首页Android知识
从custom Drawable看invalidateSelf(

从custom Drawable看invalidateSelf(

作者: dotdog | 来源:发表于2016-09-18 12:52 被阅读1793次

    一、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)开始找ViewDrawable的关系

    /**
     * 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) 描述的,ViewDrawable各司其职。

    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官方文档描述DrawableinvalidateSelf()如下:

    invalidateSelf()
    Use the current Drawable.Callback
    implementation to have this Drawable redrawn.

    1.查看DrawableinvalidateSelf()源码如下。
    所以当Drawable内部或者其对象调用invalidateSelf()的时候,便以Drawable对象自身为参数,让类ImageView来调用实现了Drawable.CallbackinvalidateDrawable(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)。

    相关文章

      网友评论

        本文标题:从custom Drawable看invalidateSelf(

        本文链接:https://www.haomeiwen.com/subject/ucowettx.html