1. 视图状态
1>:enable:是否可用,setEnable(),true可用,false不可用,区别在于不可用的view不能响应 onTouch;
2>:focused:是否获取焦点,如EditText,focuseable && focuseable in touch mode 成立,可以获取焦点;
3>:selected:是否选中,setSelected(),true选中,false未选中;
4>:pressed:是否按下,setPressed(),true按下,false未按下;
2. 源码分析
对于pressed:手指按下,pressed=true,
view.drawableStateChanged__getDrawableState__onCreateDrawableState__
drawable.setState__onStateChange
StateListDrawable.onStateChange__selectDrawable
手指按下后,pressed=true,会调用 view.drawableStateChanged
protected void drawableStateChanged() {
// 获取当前 view 状态的 int[] 数组
final int[] state = getDrawableState();
boolean changed = false;
// 把 mBackground 赋值给 Drawable ,mBackground 就是自己在drawable下边创建的 selector文件
final Drawable bg = mBackground;
if (bg != null && bg.isStateful()) {
// 获取当前 view 的状态的 int[] 数组后,调用 setState() 更新状态
changed |= bg.setState(state);
}
}
public final int[] getDrawableState() {
// 首先判断当前view状态 是否发生变化,如果没有改变,就直接返回当前view状态
if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) {
return mDrawableState;
} else {
// 如果当前view状态改变了,调用 onCreateDrawableState() 获取最新状态,
// 所有状态会以 int[] 数组返回
mDrawableState = onCreateDrawableState(0);
mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY;
return mDrawableState;
}
}
public boolean setState(@NonNull final int[] stateSet) {
// 用 Arrays.equals()判断 view状态的int[] 数组是否发生变化,如果变化就调用 onStateChange,
// 如果没有变化,就返回 false , Drawable 中的 onStateChange 只返回false,没有任何逻辑,
// 因为 mBackground 是通过 selector创建的,而通过 selector创建的 drawable对象 是
// StateListDrawable实例对象,这里的 onStateChange() 就是 StateListDrawable 的 onStateChange
if (!Arrays.equals(mStateSet, stateSet)) {
mStateSet = stateSet;
return onStateChange(stateSet);
}
return false;
}
@Override
protected boolean onStateChange(int[] stateSet) {
// indexOfStateSet:获取当前 view对应的 Drawable 下标
int idx = mStateListState.indexOfStateSet(stateSet);
// selectDrawable:把下标传入,此方法 就会把当前 view 背景设置为 当前状态对应的图片
return selectDrawable(idx) || changed;
}
分析上边源码:
1>:一个view 手指按下,pressed=true,会调用 view.drawableStateChanged,在此方法中:
- 首先判断当前view状态,如果没有变化,直接返回当前view状态;如果变了,获取当前 view 状态的 int[] 数组;
- 然后 把 mBackground赋值给 Drawable对象,然后调用 setState();
2>:在 setState 中,判断 view状态的int[] 数组是否变化,如果变化,调用 onStateChange,如果没有变,返回 false;
3>:Drawable 中的 onStateChange 只返回 false,没有任何逻辑,因为 mBackground 是通过 selector 创建的,而通过 selector创建的 drawable对象 是 StateListDrawable 实例,所以 Drawable中的 onStateChange其实就是 调用 StateListDrawable中的 onStateChange;
4>:在 onStateChange中: indexOfStateSet() 获取当前 view 对应的 Drawable 下标, selectDrawable 把当前 view 背景设置为 当前状态对应的图片;