selector<对应的drawable是StateListDrawable> 的运作原理 这一篇已经讲的很清楚了:
http://blog.youkuaiyun.com/guolin_blog/article/details/17045157
最后一步显示是通过DrawableContainer(StateListDrawable的基类)<DrawableContainer extends Drawable implements Drawable.Callback>
的selectDrawable(int idx)
然后mCurrDrawable.setVisible(......) 来实现的图像变化。
setVisible(......)在有变化的情况下调用invalidateSelf()->注册的callback->invalidateDrawable(this).........一路callback,
最后到View<View implements Drawable.Callback>->invalidateDrawable()
public void invalidateDrawable(Drawable drawable) {
if (verifyDrawable(drawable)) {
final Rect dirty = drawable.getBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
invalidate(dirty.left + scrollX, dirty.top + scrollY,
dirty.right + scrollX, dirty.bottom + scrollY);
}
}
最后还是invaldate制定的区域来实现图片的刷新.
目前项目中实现夜间模式等需要大规模切换整体UI颜色图案 就采用了这种结合selector 与 自定义 drawable 状态的方式来实现,
切换夜间模式相当于某个drawable状态发生变化,selector便会跟着改变,
当然肯定不会和系统提供的点击或者focus 变化那么简单,
因为夜间模式这种是牵一发动全身,整个UI全部换,因此,也从根View开始主动的触发强制性的refreshDrawableState()
来遍历刷新(BFS/DFS)整个UI, 并且每个view 在attach到window时,也要做相应的nighemode检测(onAttachToWindow中), 不过这么做的前提工作是每一个使用的
view都要重载DrawableState相关的函数。
/**
* Call this to force a view to update its drawable state. This will cause
* drawableStateChanged to be called on this view. Views that are interested
* in the new state should call getDrawableState.
*
* @see #drawableStateChanged
* @see #getDrawableState
*/
public void refreshDrawableState() {
mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
drawableStateChanged();
ViewParent parent = mParent;
if (parent != null) {
parent.childDrawableStateChanged(this);
}
}
parent的childDrawableStateChanged()会触发自己的refreshDrawableState()。
/**
* If {@link #addStatesFromChildren} is true, refreshes this group's
* drawable state (to include the states from its children).
*/
public void childDrawableStateChanged(View child) {
if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
refreshDrawableState();
}
}
protected void drawableStateChanged() {
Drawable d = mBackground;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
注意的这里的isStateful的判断,一般的drawable的isStateful()返回是true, 不过使用了selector的
StateListDrawable返回的是true,也定义了自己的onStateChange函数(在setState变化的时候调用)
}
}