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

    有多种因素会导致触发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

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/androiddevelop/article/details/8536028
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞