天天记录 - Android refreshDrawableState源码及流程简单分析

来源:互联网 发布:公司如何开淘宝店 编辑:程序博客网 时间:2024/05/16 05:43


    有多种因素会导致触发refreshDrawableState,当前只考虑其中一种setPressed即设置视图是否处于被按下状态。其他会触发此方法的有focusChanged等。

    原理是定义不同状态的图片,系统进行状态监听例如在onTouchEvent中判断当前在什么状态,再根据之前提供的图片进行设置并重绘显示效果。

    以下是根据代码一个具体的流程,其中解释的并不是太多,当前也都比较简单都是直接的方法调用顺序。

    
    先来看看View.setPressed源码
    public void setPressed(boolean pressed) {        if (pressed) {            mPrivateFlags |= PRESSED ;        } else {            mPrivateFlags &= ~PRESSED;        }        refreshDrawableState();        dispatchSetPressed(pressed);    }



    其中调用了View.refreshDrawableState,下面查看一下相关代码View.refreshDrawableState与 View.drawableStateChanged:



    public void refreshDrawableState() {// 用于判断是否发生状态变化        mPrivateFlags |= DRAWABLE_STATE_DIRTY ;        // 状态改变后进行绘制        drawableStateChanged();        ViewParent parent = mParent;        if (parent != null) {            // 父视图如果存在的话执行            parent.childDrawableStateChanged( this);        }    }    // 仅在ViewGroup覆写    protected void drawableStateChanged() {    // 当前视图的背景图        Drawable d = mBGDrawable;        if (d != null && d.isStateful()) {            // 为当前drawable设置当前drawable状态索引            d.setState(getDrawableState());        }    }        // 获取视图的当前状态    public final int[] getDrawableState() {        if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) {            return mDrawableState;        } else {            // 将视图状态转换为一个int[]数组            // DrawableState可以识别此数组            mDrawableState = onCreateDrawableState(0);            mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY;            return mDrawableState;        }    }




二  以上在View中调用Drawable相应方法Drawable.setState 和 Drawable.onStateChange
    public boolean setState(final int[] stateSet) {        if (!Arrays.equals( mStateSet, stateSet)) {            mStateSet = stateSet;            return onStateChange(stateSet);        }        return false ;    }     protected boolean onStateChange (int[] state) { return false; }




三  步骤二中的调用的方法是一个回调,其具体实现在其子类中,此处仅罗列针对其子类StateListDrawable的具体实现代码StateListDrawable.onStateChange和 StateListDrawable.selectDrawable
    @Override    protected boolean onStateChange( int[] stateSet) {        int idx = mStateListState.indexOfStateSet(stateSet);        if (idx < 0) {            idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);        }        if (selectDrawable(idx)) {            return true ;        }        return super .onStateChange(stateSet);    }    public boolean selectDrawable( int idx)    {            ......        // 触发绘制请求        invalidateSelf();        return true ;    }




四  StateListDrawable以上方法流程中调用的方法invalidateSelf,由其父类中进行具体实现Drawable.Callback.invalidateSelfe和Drawable.Callback.invalidateDrawable
public void invalidateSelf(){// mCallback是在何处赋赋值?    if (mCallback != null) {        mCallback.invalidateDrawable(this);    }}// 全局搜索发现此处对其值进行赋值,那何处引用了此方法呢?public final void setCallback(Callback cb) {    mCallback = new WeakReference<Callback>(cb);}public void invalidateDrawable (Drawable who);




五  以上步骤需要调用其setCallback传入cb才行,具体什么地方传入的呢?具体是在View.setBackgroundDrawable中
    @Deprecated    public void setBackgroundDrawable(Drawable background) {    ...    // 此处设置Callback,当前View就是其Callback    background.setCallback(this);    ...    mBGDrawable = background;    }


六 从步骤五可以获知drawable中的Callback就是当前View自身,View实现Drawable.Callback

    public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Callback,AccessibilityEventSource {            public void invalidateDrawable(Drawable drawable) {            if (verifyDrawable(drawable)) {                final Rect dirty = drawable.getBounds();                final int scrollX = mScrollX;                final int scrollY = mScrollY;                // 看到了熟悉的invalidate,之后就是走正常的invalidate流程                invalidate(dirty. left + scrollX, dirty.top + scrollY,                        dirty. right + scrollX, dirty.bottom + scrollY);            }        }        }

第六步中进行具体的请求刷新



参考资料:

《Android 内核剖析》 柯元丹 著  13.6.3 refreshDrawableList 

Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解

代码实现ColorStateList及StateListDrawable




原创粉丝点击