DrawableWrapper 与其说是个 Drawable ,倒不如说是一个容器。
它内部保存了一个 mDrawable,让 mDrawable 全权负责一切,而自己则对 mDrawable 做一些加工。
public void setDrawable(@Nullable Drawable dr) {
if (mDrawable != null) {
mDrawable.setCallback(null);
}
mDrawable = dr;
if (dr != null) {
dr.setCallback(this);
// Only call setters for data that's stored in the base Drawable.
dr.setVisible(isVisible(), true);
dr.setState(getState());
dr.setLevel(getLevel());
dr.setBounds(getBounds());
dr.setLayoutDirection(getLayoutDirection());
if (mState != null) {
mState.mDrawableState = dr.getConstantState();
}
}
invalidateSelf();
}
@Override
public void draw(@NonNull Canvas canvas) {
if (mDrawable != null) {
mDrawable.draw(canvas);
}
}
比如它的实现类 InsetDrawable。(这个类比较简单,所以更能看出 DrawableWrapper 的作用是什么。)
@Override
protected void onBoundsChange(Rect bounds) {
final Rect r = mTmpRect;
r.set(bounds);
r.left += mState.mInsetLeft;
r.top += mState.mInsetTop;
r.right -= mState.mInsetRight;
r.bottom -= mState.mInsetBottom;
// Apply inset bounds to the wrapped drawable.
super.onBoundsChange(r);
}
@Override
protected void onBoundsChange(@NonNull Rect bounds) {
if (mDrawable != null) {
mDrawable.setBounds(bounds);
}
}
InsetDrawable 只做了一件事:根据 inset 压缩 mDrawable 的 bounds,从而在背景上实现了类似内边距的效果。
ClipDrawable:
@Override
public void draw(Canvas canvas) {
final Drawable dr = getDrawable();
if (dr.getLevel() == 0) {
return;
}
final Rect r = mTmpRect;
final Rect bounds = getBounds();
final int level = getLevel();
int w = bounds.width();
final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
if ((mState.mOrientation & HORIZONTAL) != 0) {
w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;
}
int h = bounds.height();
final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
if ((mState.mOrientation & VERTICAL) != 0) {
h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;
}
final int layoutDirection = getLayoutDirection();
Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
if (w > 0 && h > 0) {
canvas.save();
canvas.clipRect(r);
dr.draw(canvas);
canvas.restore();
}
}
关键是在绘制前调用了 canvas.clipRect(r),所以绘制的结果就只能是 mDrawable 的一部分。
而这个 r 是由 level 和方向属性控制的。
实现类的还有 RotateDrawable 和 ScaleDrawable ,都是类似的。