Add root alpha and animation to (Animated)VectorDrawable
b/17393626 Change-Id: If6a28b072f7d4bcb2b57022d86ec784f4c0d78f1
This commit is contained in:
@@ -5271,11 +5271,16 @@
|
||||
<attr name="viewportWidth" format="float"/>
|
||||
<!-- The height of the canvas the drawing is on. -->
|
||||
<attr name="viewportHeight" format="float"/>
|
||||
<!-- The name of this vector drawable -->
|
||||
<attr name="name" />
|
||||
<!-- The opacity of the whole vector drawable, as a value between 0
|
||||
(completely transparent) and 1 (completely opaque). -->
|
||||
<attr name="alpha" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Defines the group used in VectorDrawables. -->
|
||||
<declare-styleable name="VectorDrawableGroup">
|
||||
<!-- The Name of this group -->
|
||||
<!-- The name of this group -->
|
||||
<attr name="name" />
|
||||
<!-- The amount to rotate the group -->
|
||||
<attr name="rotation" />
|
||||
@@ -5295,7 +5300,7 @@
|
||||
|
||||
<!-- Defines the path used in VectorDrawables. -->
|
||||
<declare-styleable name="VectorDrawablePath">
|
||||
<!-- The Name of this path -->
|
||||
<!-- The name of this path -->
|
||||
<attr name="name" />
|
||||
<!-- The width a path stroke -->
|
||||
<attr name="strokeWidth" format="float" />
|
||||
|
||||
@@ -256,21 +256,22 @@ public class VectorDrawable extends Drawable {
|
||||
}
|
||||
|
||||
if (!mAllowCaching) {
|
||||
mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
|
||||
// AnimatedVectorDrawable
|
||||
if (!mVectorState.hasTranslucentRoot()) {
|
||||
mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
|
||||
} else {
|
||||
mVectorState.createCachedBitmapIfNeeded(bounds);
|
||||
mVectorState.updateCachedBitmap(bounds);
|
||||
mVectorState.drawCachedBitmapWithRootAlpha(canvas);
|
||||
}
|
||||
} else {
|
||||
Bitmap bitmap = mVectorState.mCachedBitmap;
|
||||
if (bitmap == null || !mVectorState.canReuseCache(bounds.width(),
|
||||
bounds.height())) {
|
||||
bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas tmpCanvas = new Canvas(bitmap);
|
||||
mVectorState.mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height());
|
||||
mVectorState.mCachedBitmap = bitmap;
|
||||
|
||||
// Static Vector Drawable case.
|
||||
mVectorState.createCachedBitmapIfNeeded(bounds);
|
||||
if (!mVectorState.canReuseCache()) {
|
||||
mVectorState.updateCachedBitmap(bounds);
|
||||
mVectorState.updateCacheStates();
|
||||
}
|
||||
// The bitmap's size is the same as the bounds.
|
||||
canvas.drawBitmap(bitmap, 0, 0, null);
|
||||
mVectorState.drawCachedBitmapWithRootAlpha(canvas);
|
||||
}
|
||||
|
||||
canvas.restoreToCount(saveCount);
|
||||
@@ -492,6 +493,15 @@ public class VectorDrawable extends Drawable {
|
||||
throw new XmlPullParserException(a.getPositionDescription() +
|
||||
"<vector> tag requires height > 0");
|
||||
}
|
||||
|
||||
final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
|
||||
pathRenderer.getAlpha());
|
||||
pathRenderer.setAlpha(alphaInFloat);
|
||||
|
||||
pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name);
|
||||
if (pathRenderer.mRootName != null) {
|
||||
pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
|
||||
@@ -646,15 +656,60 @@ public class VectorDrawable extends Drawable {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canReuseCache(int width, int height) {
|
||||
// TODO: Support colorFilter here.
|
||||
public void drawCachedBitmapWithRootAlpha(Canvas canvas) {
|
||||
Paint alphaPaint = getRootAlphaPaint();
|
||||
// The bitmap's size is the same as the bounds.
|
||||
canvas.drawBitmap(mCachedBitmap, 0, 0, alphaPaint);
|
||||
}
|
||||
|
||||
public boolean hasTranslucentRoot() {
|
||||
return mVPathRenderer.getRootAlpha() < 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null when there is no need for alpha paint.
|
||||
*/
|
||||
public Paint getRootAlphaPaint() {
|
||||
Paint paint = null;
|
||||
boolean needsAlphaPaint = hasTranslucentRoot();
|
||||
if (needsAlphaPaint) {
|
||||
paint = new Paint();
|
||||
paint.setAlpha(mVPathRenderer.getRootAlpha());
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
public void updateCachedBitmap(Rect bounds) {
|
||||
mCachedBitmap.eraseColor(Color.TRANSPARENT);
|
||||
Canvas tmpCanvas = new Canvas(mCachedBitmap);
|
||||
mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height());
|
||||
}
|
||||
|
||||
public void createCachedBitmapIfNeeded(Rect bounds) {
|
||||
if (mCachedBitmap == null || !canReuseBitmap(bounds.width(),
|
||||
bounds.height())) {
|
||||
mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean canReuseBitmap(int width, int height) {
|
||||
if (width == mCachedBitmap.getWidth()
|
||||
&& height == mCachedBitmap.getHeight()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canReuseCache() {
|
||||
if (!mCacheDirty
|
||||
&& mCachedThemeAttrs == mThemeAttrs
|
||||
&& mCachedTint == mTint
|
||||
&& mCachedTintMode == mTintMode
|
||||
&& mCachedAutoMirrored == mAutoMirrored
|
||||
&& width == mCachedBitmap.getWidth()
|
||||
&& height == mCachedBitmap.getHeight()
|
||||
&& mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
|
||||
&& mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -729,7 +784,8 @@ public class VectorDrawable extends Drawable {
|
||||
float mBaseHeight = 0;
|
||||
float mViewportWidth = 0;
|
||||
float mViewportHeight = 0;
|
||||
private int mRootAlpha = 0xFF;
|
||||
int mRootAlpha = 0xFF;
|
||||
String mRootName = null;
|
||||
|
||||
final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
|
||||
|
||||
@@ -747,6 +803,17 @@ public class VectorDrawable extends Drawable {
|
||||
return mRootAlpha;
|
||||
}
|
||||
|
||||
// setAlpha() and getAlpha() are used mostly for animation purpose, since
|
||||
// Animator like to use alpha from 0 to 1.
|
||||
public void setAlpha(float alpha) {
|
||||
setRootAlpha((int) (alpha * 255));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getAlpha() {
|
||||
return getRootAlpha() / 255.0f;
|
||||
}
|
||||
|
||||
public VPathRenderer(VPathRenderer copy) {
|
||||
mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
|
||||
mPath = new Path(copy.mPath);
|
||||
@@ -757,6 +824,10 @@ public class VectorDrawable extends Drawable {
|
||||
mViewportHeight = copy.mViewportHeight;
|
||||
mChangingConfigurations = copy.mChangingConfigurations;
|
||||
mRootAlpha = copy.mRootAlpha;
|
||||
mRootName = copy.mRootName;
|
||||
if (copy.mRootName != null) {
|
||||
mVGTargetsMap.put(copy.mRootName, this);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canApplyTheme() {
|
||||
@@ -856,7 +927,7 @@ public class VectorDrawable extends Drawable {
|
||||
}
|
||||
|
||||
private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h) {
|
||||
final float scaleX = w / mViewportWidth;
|
||||
final float scaleX = w / mViewportWidth;
|
||||
final float scaleY = h / mViewportHeight;
|
||||
final float minScale = Math.min(scaleX, scaleY);
|
||||
|
||||
@@ -1219,7 +1290,7 @@ public class VectorDrawable extends Drawable {
|
||||
/**
|
||||
* Clip path, which only has name and pathData.
|
||||
*/
|
||||
private static class VClipPath extends VPath{
|
||||
private static class VClipPath extends VPath {
|
||||
public VClipPath() {
|
||||
// Empty constructor.
|
||||
}
|
||||
|
||||
25
tests/VectorDrawableTest/res/anim/trim_path_animation06.xml
Normal file
25
tests/VectorDrawableTest/res/anim/trim_path_animation06.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<objectAnimator
|
||||
android:duration="9000"
|
||||
android:propertyName="alpha"
|
||||
android:valueFrom="1.0"
|
||||
android:valueTo="0.0"/>
|
||||
|
||||
</set>
|
||||
@@ -37,5 +37,8 @@
|
||||
<target
|
||||
android:name="rotationGroup"
|
||||
android:animation="@anim/trim_path_animation04" />
|
||||
<target
|
||||
android:name="rootGroup"
|
||||
android:animation="@anim/trim_path_animation06" />
|
||||
|
||||
</animated-vector>
|
||||
@@ -14,10 +14,12 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="rootGroup"
|
||||
android:height="64dp"
|
||||
android:width="64dp"
|
||||
android:viewportHeight="600"
|
||||
android:viewportWidth="600" >
|
||||
android:viewportWidth="600"
|
||||
android:alpha="0.5" >
|
||||
|
||||
<group
|
||||
android:name="rotationGroup"
|
||||
|
||||
@@ -31,6 +31,8 @@ public class AnimatedVectorDrawableTest extends Activity implements View.OnClick
|
||||
R.drawable.animation_vector_progress_bar,
|
||||
R.drawable.animation_vector_drawable_favorite,
|
||||
R.drawable.animation_vector_drawable01,
|
||||
// Duplicate to test constant state.
|
||||
R.drawable.animation_vector_drawable01,
|
||||
};
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user