上篇文章我们已经找到我们要跟换图标的地方也即是SystemUI 模块
com.android.systemui/qs/tiles/下的XXXXTile 。在这里我们用飞行模式作为示例。
AirplaneModeTile类图大致如下:
我们只需要关注圈中的那些变量或者方法就可以,首先我们进入handUpdateState方法中,字面意思大家应该能猜到就是处理状态变化。
下面我们就来分析此方法,首先先看源码,我摘取了一些必要的
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
boolean airplaneMode = value != 0;
........
if (airplaneMode) {//打开状态赋值
state.icon = mEnable;
state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_airplane_on);
} else {//关闭状态赋值
state.icon = mDisable;
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_airplane_off);
}
}
从源码可以看出分别对飞行模式下的打开和关闭两种状态做赋值操作,从而切换图片。这里我们如何换成自己的呢?
state.icon = mEnable;
查看state :BooleanState,是父类QSTile 的内部类
public static class BooleanState extends State {
public boolean value;
@Override
public boolean copyTo(State other) {
final BooleanState o = (BooleanState) other;
final boolean changed = super.copyTo(other) || o.value != value;
o.value = value;
return changed;
}
@Override
protected StringBuilder toStringBuilder() {
final StringBuilder rt = super.toStringBuilder();
rt.insert(rt.length() - 1, ",value=" + value);
return rt;
}
}
没有我们需要的Icon,追溯父类
State :
public static class State {
........
public Icon icon;
.......
}
Icon :
public static abstract class Icon {
abstract public Drawable getDrawable(Context context);
@Override
public int hashCode() {
return Icon.class.hashCode();
}
}
这里可以发现Icon 是一个抽象类,类型也就是一个Drawable。
这里我们在回到 AirplaneModeTile:
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation);
state.icon = mEnable;
这里icon 是一个 AnimationIcon
protected class AnimationIcon extends ResourceIcon {
private boolean mAllowAnimation;
public AnimationIcon(int resId) {
super(resId);//调用了ResourceIcon
}
public void setAllowAnimation(boolean allowAnimation) {
mAllowAnimation = allowAnimation;
}
@Override
public Drawable getDrawable(Context context) {
// workaround: get a clean state for every new AVD
final AnimatedVectorDrawable d = (AnimatedVectorDrawable) super.getDrawable(context)
.getConstantState().newDrawable();
d.start();
if (mAllowAnimation) {
mAllowAnimation = false;
} else {
d.stop(); // skip directly to end state
}
return d;
}
}
ResourceIcon :
public static class ResourceIcon extends Icon {
private static final SparseArray<Icon> ICONS = new SparseArray<Icon>();
private final int mResId;
private ResourceIcon(int resId) {
mResId = resId;
}
public static Icon get(int resId) {
Icon icon = ICONS.get(resId);
if (icon == null) {
icon = new ResourceIcon(resId);
ICONS.put(resId, icon);
}
return icon;
}
@Override
public Drawable getDrawable(Context context) {
return context.getDrawable(mResId);
}
}
回到AnimationIcon
@Override
public Drawable getDrawable(Context context) {
// workaround: get a clean state for every new AVD
final AnimatedVectorDrawable d = (AnimatedVectorDrawable) super.getDrawable(context)
.getConstantState().newDrawable();
d.start();
if (mAllowAnimation) {
mAllowAnimation = false;
} else {
d.stop(); // skip directly to end state
}
return d;
}
这里是最主要的,应用了AnimatedVectorDrawable 动态矢量图
,这里我们先不看,可以做为特定的一点去学习。
到这里我们明白飞行模式的图标就是一个矢量图,因为目前我手上给的是图片,所以就不能简单的就替换
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation);
为自己 的图标。这里怎么办呢?我们不需要动画,所以我们就找到AnimationIcon 的父亲ResourceIcon它的Drawable getDrawable()
就是我们要用到的所以我们就可以在AirplaneModeTile
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
boolean airplaneMode = value != 0;
........
if (airplaneMode) {//打开状态赋值
//加上自己的图标
if(是换自己的UI)
{
state.icon = ResourceIcon.get(R.drawable.自己的图标);
}else{
state.icon = mEnable;
}
state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_airplane_on);
} else {//关闭状态赋值
//此处同理
state.icon = mDisable;
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_airplane_off);
}
}
好了图标就换成功啦。