am 8b455841: am 094c82ad: Merge "Scaling (Animated)VectorDrawable inside ImageView" into mnc-dev

* commit '8b455841d9da1ac5ddf1b88e03c0c94613fd4046':
  Scaling (Animated)VectorDrawable inside ImageView
This commit is contained in:
ztenghui
2015-07-17 20:45:56 +00:00
committed by Android Git Automerger
2 changed files with 66 additions and 34 deletions

View File

@ -200,6 +200,11 @@ public class VectorDrawable extends Drawable {
private static final int LINEJOIN_ROUND = 1; private static final int LINEJOIN_ROUND = 1;
private static final int LINEJOIN_BEVEL = 2; private static final int LINEJOIN_BEVEL = 2;
// Cap the bitmap size, such that it won't hurt the performance too much
// and it won't crash due to a very large scale.
// The drawable will look blurry above this size.
private static final int MAX_CACHED_BITMAP_SIZE = 2048;
private static final boolean DBG_VECTOR_DRAWABLE = false; private static final boolean DBG_VECTOR_DRAWABLE = false;
private VectorDrawableState mVectorState; private VectorDrawableState mVectorState;
@ -219,6 +224,11 @@ public class VectorDrawable extends Drawable {
private int mDpiScaledHeight = 0; private int mDpiScaledHeight = 0;
private Insets mDpiScaleInsets = Insets.NONE; private Insets mDpiScaleInsets = Insets.NONE;
// Temp variable, only for saving "new" operation at the draw() time.
private final float[] mTmpFloats = new float[9];
private final Matrix mTmpMatrix = new Matrix();
private final Rect mTmpBounds = new Rect();
public VectorDrawable() { public VectorDrawable() {
this(null, null); this(null, null);
} }
@ -262,44 +272,59 @@ public class VectorDrawable extends Drawable {
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
final Rect bounds = getBounds(); // We will offset the bounds for drawBitmap, so copyBounds() here instead
if (bounds.width() <= 0 || bounds.height() <= 0) { // of getBounds().
copyBounds(mTmpBounds);
if (mTmpBounds.width() <= 0 || mTmpBounds.height() <= 0) {
// Nothing to draw // Nothing to draw
return; return;
} }
final int saveCount = canvas.save(); // Color filters always override tint filters.
final boolean needMirroring = needMirroring(); final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
canvas.translate(bounds.left, bounds.top); // The imageView can scale the canvas in different ways, in order to
// avoid blurry scaling, we have to draw into a bitmap with exact pixel
// size first. This bitmap size is determined by the bounds and the
// canvas scale.
canvas.getMatrix(mTmpMatrix);
mTmpMatrix.getValues(mTmpFloats);
float canvasScaleX = Math.abs(mTmpFloats[Matrix.MSCALE_X]);
float canvasScaleY = Math.abs(mTmpFloats[Matrix.MSCALE_Y]);
int scaledWidth = (int) (mTmpBounds.width() * canvasScaleX);
int scaledHeight = (int) (mTmpBounds.height() * canvasScaleY);
scaledWidth = Math.min(MAX_CACHED_BITMAP_SIZE, scaledWidth);
scaledHeight = Math.min(MAX_CACHED_BITMAP_SIZE, scaledHeight);
if (scaledWidth <= 0 || scaledHeight <= 0) {
return;
}
final int saveCount = canvas.save();
canvas.translate(mTmpBounds.left, mTmpBounds.top);
// Handle RTL mirroring.
final boolean needMirroring = needMirroring();
if (needMirroring) { if (needMirroring) {
canvas.translate(bounds.width(), 0); canvas.translate(mTmpBounds.width(), 0);
canvas.scale(-1.0f, 1.0f); canvas.scale(-1.0f, 1.0f);
} }
// Color filters always override tint filters. // At this point, canvas has been translated to the right position.
final ColorFilter colorFilter = mColorFilter == null ? mTintFilter : mColorFilter; // And we use this bound for the destination rect for the drawBitmap, so
// we offset to (0, 0);
mTmpBounds.offsetTo(0, 0);
mVectorState.createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
if (!mAllowCaching) { if (!mAllowCaching) {
// AnimatedVectorDrawable mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
if (!mVectorState.hasTranslucentRoot()) {
mVectorState.mVPathRenderer.draw(
canvas, bounds.width(), bounds.height(), colorFilter);
} else {
mVectorState.createCachedBitmapIfNeeded(bounds);
mVectorState.updateCachedBitmap(bounds);
mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter);
}
} else { } else {
// Static Vector Drawable case.
mVectorState.createCachedBitmapIfNeeded(bounds);
if (!mVectorState.canReuseCache()) { if (!mVectorState.canReuseCache()) {
mVectorState.updateCachedBitmap(bounds); mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
mVectorState.updateCacheStates(); mVectorState.updateCacheStates();
} }
mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter);
} }
mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter, mTmpBounds);
canvas.restoreToCount(saveCount); canvas.restoreToCount(saveCount);
} }
@ -770,10 +795,11 @@ public class VectorDrawable extends Drawable {
} }
} }
public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter) { public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter,
Rect originalBounds) {
// The bitmap's size is the same as the bounds. // The bitmap's size is the same as the bounds.
final Paint p = getPaint(filter); final Paint p = getPaint(filter);
canvas.drawBitmap(mCachedBitmap, 0, 0, p); canvas.drawBitmap(mCachedBitmap, null, originalBounds, p);
} }
public boolean hasTranslucentRoot() { public boolean hasTranslucentRoot() {
@ -797,16 +823,15 @@ public class VectorDrawable extends Drawable {
return mTempPaint; return mTempPaint;
} }
public void updateCachedBitmap(Rect bounds) { public void updateCachedBitmap(int width, int height) {
mCachedBitmap.eraseColor(Color.TRANSPARENT); mCachedBitmap.eraseColor(Color.TRANSPARENT);
Canvas tmpCanvas = new Canvas(mCachedBitmap); Canvas tmpCanvas = new Canvas(mCachedBitmap);
mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height(), null); mVPathRenderer.draw(tmpCanvas, width, height, null);
} }
public void createCachedBitmapIfNeeded(Rect bounds) { public void createCachedBitmapIfNeeded(int width, int height) {
if (mCachedBitmap == null || !canReuseBitmap(bounds.width(), if (mCachedBitmap == null || !canReuseBitmap(width, height)) {
bounds.height())) { mCachedBitmap = Bitmap.createBitmap(width, height,
mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
Bitmap.Config.ARGB_8888); Bitmap.Config.ARGB_8888);
mCacheDirty = true; mCacheDirty = true;
} }

View File

@ -37,8 +37,8 @@ public class ScaleDrawableTests extends Activity {
}; };
protected int icon = R.drawable.bitmap_drawable01; protected int icon = R.drawable.bitmap_drawable01;
protected int vector_icon = R.drawable.vector_drawable16; protected int vector_icon = R.drawable.vector_drawable16;
protected int animated_vector_icon = R.drawable.ic_hourglass_animation;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -46,12 +46,12 @@ public class ScaleDrawableTests extends Activity {
ScrollView scrollView = new ScrollView(this); ScrollView scrollView = new ScrollView(this);
GridLayout container = new GridLayout(this); GridLayout container = new GridLayout(this);
scrollView.addView(container); scrollView.addView(container);
container.setColumnCount(3); container.setColumnCount(4);
container.setBackgroundColor(0xFF888888); container.setBackgroundColor(0xFF888888);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
params.width = 400; params.width = 300;
params.height = 300; params.height = 200;
for (int i = 0; i < scaleTypes.length; i++) { for (int i = 0; i < scaleTypes.length; i++) {
TextView t = new TextView(this); TextView t = new TextView(this);
@ -71,6 +71,13 @@ public class ScaleDrawableTests extends Activity {
view.setScaleType(scaleType); view.setScaleType(scaleType);
view.setImageResource(vector_icon); view.setImageResource(vector_icon);
container.addView(view); container.addView(view);
ImageView avd_view = new ImageView(this);
avd_view.setLayoutParams(params);
avd_view.setScaleType(scaleType);
avd_view.setImageResource(animated_vector_icon);
container.addView(avd_view);
} }
setContentView(scrollView); setContentView(scrollView);