summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Mount <mount@google.com>2014-06-24 09:36:18 -0700
committerGeorge Mount <mount@google.com>2014-06-25 13:45:16 -0700
commit990205eada00ad3e575761d19607bb03e12f9aa3 (patch)
tree5e3158f1ee3d41334f7e2830ae4df3eee3c0577e
parent16ffa8d3ef3d0a45efbca9fa7b4b32ba4ebd1e07 (diff)
downloadframeworks_base-990205eada00ad3e575761d19607bb03e12f9aa3.zip
frameworks_base-990205eada00ad3e575761d19607bb03e12f9aa3.tar.gz
frameworks_base-990205eada00ad3e575761d19607bb03e12f9aa3.tar.bz2
Don't use overlay to transition ImageViews.
Bug 15744992 MoveImage used an overlay to transition ImageViews. This caused strange problems when ImageViews were contained in other Views. The new ChangeImageTransform does a smooth transition for changes in scale type and bounds. Change-Id: Ia5021f4828f8f818a8699b3bdd38437aeba1cfc8
-rw-r--r--api/current.txt12
-rw-r--r--core/java/android/transition/ChangeImageTransform.java234
-rw-r--r--core/java/android/transition/MatrixClippedDrawable.java300
-rw-r--r--core/java/android/transition/MoveImage.java341
-rw-r--r--core/java/android/transition/Transition.java4
-rw-r--r--core/java/android/transition/TransitionInflater.java3
-rw-r--r--core/java/android/view/Window.java2
-rw-r--r--core/java/android/widget/ImageView.java14
-rw-r--r--core/res/res/transition/move.xml17
9 files changed, 273 insertions, 654 deletions
diff --git a/api/current.txt b/api/current.txt
index a678773..e541c66 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30466,6 +30466,12 @@ package android.transition {
method public void captureStartValues(android.transition.TransitionValues);
}
+ public class ChangeImageTransform extends android.transition.Transition {
+ ctor public ChangeImageTransform();
+ method public void captureEndValues(android.transition.TransitionValues);
+ method public void captureStartValues(android.transition.TransitionValues);
+ }
+
public class ChangeTransform extends android.transition.Transition {
ctor public ChangeTransform();
method public void captureEndValues(android.transition.TransitionValues);
@@ -30489,12 +30495,6 @@ package android.transition {
field public static final int OUT = 2; // 0x2
}
- public class MoveImage extends android.transition.Transition {
- ctor public MoveImage();
- method public void captureEndValues(android.transition.TransitionValues);
- method public void captureStartValues(android.transition.TransitionValues);
- }
-
public final class Scene {
ctor public Scene(android.view.ViewGroup);
ctor public Scene(android.view.ViewGroup, android.view.View);
diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java
new file mode 100644
index 0000000..b003690
--- /dev/null
+++ b/core/java/android/transition/ChangeImageTransform.java
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+package android.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TypeEvaluator;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.Property;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import java.util.Map;
+
+/**
+ * Transitions changes in ImageView {@link ImageView#setScaleType(ImageView.ScaleType)} as
+ * well as image scaling due to ImageView size changes. When combined with
+ * {@link android.transition.ChangeBounds}, an ImageView that changes size will
+ * scale smoothly.
+ */
+public class ChangeImageTransform extends Transition {
+
+ private static final String TAG = "ChangeScaleType";
+
+ private static final String PROPNAME_MATRIX = "android:changeScaleType:matrix";
+ private static final String PROPNAME_BOUNDS = "android:changeScaleType:bounds";
+
+ private static final String[] sTransitionProperties = {
+ PROPNAME_MATRIX,
+ PROPNAME_BOUNDS,
+ };
+
+ private static TypeEvaluator<Matrix> NULL_MATRIX_EVALUATOR = new TypeEvaluator<Matrix>() {
+ @Override
+ public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
+ return null;
+ }
+ };
+
+ private static Property<ImageView, Matrix> ANIMATED_TRANSFORM_PROPERTY
+ = new Property<ImageView, Matrix>(Matrix.class, "animatedTransform") {
+ @Override
+ public void set(ImageView object, Matrix value) {
+ object.animateTransform(value);
+ }
+
+ @Override
+ public Matrix get(ImageView object) {
+ return null;
+ }
+ };
+
+ private void captureValues(TransitionValues transitionValues) {
+ View view = transitionValues.view;
+ if (!(view instanceof ImageView) || view.getVisibility() != View.VISIBLE) {
+ return;
+ }
+ ImageView imageView = (ImageView) view;
+ Drawable drawable = imageView.getDrawable();
+ if (drawable == null) {
+ return;
+ }
+ Map<String, Object> values = transitionValues.values;
+
+ int left = view.getLeft();
+ int top = view.getTop();
+ int right = view.getRight();
+ int bottom = view.getBottom();
+
+ Rect bounds = new Rect(left, top, right, bottom);
+ values.put(PROPNAME_BOUNDS, bounds);
+ Matrix matrix;
+ ImageView.ScaleType scaleType = imageView.getScaleType();
+ if (scaleType == ImageView.ScaleType.FIT_XY) {
+ matrix = imageView.getImageMatrix();
+ if (!matrix.isIdentity()) {
+ matrix = new Matrix(matrix);
+ } else {
+ int drawableWidth = drawable.getIntrinsicWidth();
+ int drawableHeight = drawable.getIntrinsicHeight();
+ if (drawableWidth > 0 && drawableHeight > 0) {
+ float scaleX = ((float) bounds.width()) / drawableWidth;
+ float scaleY = ((float) bounds.height()) / drawableHeight;
+ matrix = new Matrix();
+ matrix.setScale(scaleX, scaleY);
+ } else {
+ matrix = null;
+ }
+ }
+ } else {
+ matrix = new Matrix(imageView.getImageMatrix());
+ }
+ values.put(PROPNAME_MATRIX, matrix);
+ }
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public String[] getTransitionProperties() {
+ return sTransitionProperties;
+ }
+
+ /**
+ * Creates an Animator for ImageViews moving, changing dimensions, and/or changing
+ * {@link android.widget.ImageView.ScaleType}.
+ *
+ * @param sceneRoot The root of the transition hierarchy.
+ * @param startValues The values for a specific target in the start scene.
+ * @param endValues The values for the target in the end scene.
+ * @return An Animator to move an ImageView or null if the View is not an ImageView,
+ * the Drawable changed, the View is not VISIBLE, or there was no change.
+ */
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return null;
+ }
+ Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
+ Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+ if (startBounds == null || endBounds == null) {
+ return null;
+ }
+
+ Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
+ Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
+
+ boolean matricesEqual = (startMatrix == null && endMatrix == null) ||
+ (startMatrix != null && startMatrix.equals(endMatrix));
+
+ if (startBounds.equals(endBounds) && matricesEqual) {
+ return null;
+ }
+
+ ImageView imageView = (ImageView) endValues.view;
+ Drawable drawable = imageView.getDrawable();
+ int drawableWidth = drawable.getIntrinsicWidth();
+ int drawableHeight = drawable.getIntrinsicHeight();
+
+ ObjectAnimator animator;
+ if (drawableWidth == 0 || drawableHeight == 0) {
+ animator = createNullAnimator(imageView);
+ } else {
+ if (startMatrix == null) {
+ startMatrix = Matrix.IDENTITY_MATRIX;
+ }
+ if (endMatrix == null) {
+ endMatrix = Matrix.IDENTITY_MATRIX;
+ }
+ animator = createMatrixAnimator(imageView, startMatrix, endMatrix);
+ }
+ return animator;
+ }
+
+ private ObjectAnimator createNullAnimator(ImageView imageView) {
+ return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY,
+ NULL_MATRIX_EVALUATOR, null, null);
+ }
+
+ private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix,
+ final Matrix endMatrix) {
+ ObjectAnimator animator = ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY,
+ new MatrixEvaluator(), startMatrix, endMatrix);
+ /*
+ AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+ private Matrix mPausedMatrix;
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ if (mPausedMatrix == null) {
+ mPausedMatrix = new Matrix();
+ }
+ Matrix imageMatrix = imageView.getImageMatrix();
+ mPausedMatrix.set(imageMatrix);
+ imageView.animateTransform(endMatrix);
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ imageView.animateTransform(mPausedMatrix);
+ }
+ };
+ animator.addPauseListener(listener);
+ */
+ return animator;
+ }
+
+ private static class MatrixEvaluator implements TypeEvaluator<Matrix> {
+
+ float[] mTempStartValues = new float[9];
+
+ float[] mTempEndValues = new float[9];
+
+ Matrix mTempMatrix = new Matrix();
+
+ @Override
+ public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
+ startValue.getValues(mTempStartValues);
+ endValue.getValues(mTempEndValues);
+ for (int i = 0; i < 9; i++) {
+ float diff = mTempEndValues[i] - mTempStartValues[i];
+ mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
+ }
+ mTempMatrix.setValues(mTempEndValues);
+ return mTempMatrix;
+ }
+ }
+
+}
diff --git a/core/java/android/transition/MatrixClippedDrawable.java b/core/java/android/transition/MatrixClippedDrawable.java
deleted file mode 100644
index ebaad59..0000000
--- a/core/java/android/transition/MatrixClippedDrawable.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * 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.
- */
-package android.transition;
-
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.Property;
-
-/**
- * Used in MoveImage to mock an ImageView as a Drawable to be scaled in the scene root Overlay.
- * @hide
- */
-class MatrixClippedDrawable extends Drawable implements Drawable.Callback {
- private static final String TAG = "MatrixClippedDrawable";
-
- private ClippedMatrixState mClippedMatrixState;
-
- public static final Property<MatrixClippedDrawable, Rect> CLIP_PROPERTY
- = new Property<MatrixClippedDrawable, Rect>(Rect.class, "clipRect") {
-
- @Override
- public Rect get(MatrixClippedDrawable object) {
- return object.getClipRect();
- }
-
- @Override
- public void set(MatrixClippedDrawable object, Rect value) {
- object.setClipRect(value);
- }
- };
-
- public static final Property<MatrixClippedDrawable, Matrix> MATRIX_PROPERTY
- = new Property<MatrixClippedDrawable, Matrix>(Matrix.class, "matrix") {
- @Override
- public void set(MatrixClippedDrawable object, Matrix value) {
- object.setMatrix(value);
- }
-
- @Override
- public Matrix get(MatrixClippedDrawable object) {
- return object.getMatrix();
- }
- };
-
- public MatrixClippedDrawable(Drawable drawable) {
- this(null, null);
-
- mClippedMatrixState.mDrawable = drawable;
-
- if (drawable != null) {
- drawable.setCallback(this);
- }
- }
-
- public void setMatrix(Matrix matrix) {
- if (matrix == null) {
- mClippedMatrixState.mMatrix = null;
- } else {
- if (mClippedMatrixState.mMatrix == null) {
- mClippedMatrixState.mMatrix = new Matrix();
- }
- mClippedMatrixState.mMatrix.set(matrix);
- }
- invalidateSelf();
- }
-
- public Matrix getMatrix() {
- return mClippedMatrixState.mMatrix;
- }
-
- public Rect getClipRect() {
- return mClippedMatrixState.mClipRect;
- }
-
- public void setClipRect(Rect clipRect) {
- if (clipRect == null) {
- if (mClippedMatrixState.mClipRect != null) {
- mClippedMatrixState.mClipRect = null;
- invalidateSelf();
- }
- } else {
- if (mClippedMatrixState.mClipRect == null) {
- mClippedMatrixState.mClipRect = new Rect(clipRect);
- } else {
- mClippedMatrixState.mClipRect.set(clipRect);
- }
- invalidateSelf();
- }
- }
-
- // overrides from Drawable.Callback
-
- public void invalidateDrawable(Drawable who) {
- final Drawable.Callback callback = getCallback();
- if (callback != null) {
- callback.invalidateDrawable(this);
- }
- }
-
- public void scheduleDrawable(Drawable who, Runnable what, long when) {
- final Drawable.Callback callback = getCallback();
- if (callback != null) {
- callback.scheduleDrawable(this, what, when);
- }
- }
-
- public void unscheduleDrawable(Drawable who, Runnable what) {
- final Drawable.Callback callback = getCallback();
- if (callback != null) {
- callback.unscheduleDrawable(this, what);
- }
- }
-
- // overrides from Drawable
-
- @Override
- public int getChangingConfigurations() {
- return super.getChangingConfigurations()
- | mClippedMatrixState.mChangingConfigurations
- | mClippedMatrixState.mDrawable.getChangingConfigurations();
- }
-
- @Override
- public boolean getPadding(Rect padding) {
- // XXX need to adjust padding!
- return mClippedMatrixState.mDrawable.getPadding(padding);
- }
-
- @Override
- public boolean setVisible(boolean visible, boolean restart) {
- mClippedMatrixState.mDrawable.setVisible(visible, restart);
- return super.setVisible(visible, restart);
- }
-
- @Override
- public void setAlpha(int alpha) {
- mClippedMatrixState.mDrawable.setAlpha(alpha);
- }
-
- @Override
- public int getAlpha() {
- return mClippedMatrixState.mDrawable.getAlpha();
- }
-
- @Override
- public void setColorFilter(ColorFilter cf) {
- mClippedMatrixState.mDrawable.setColorFilter(cf);
- }
-
- @Override
- public int getOpacity() {
- return mClippedMatrixState.mDrawable.getOpacity();
- }
-
- @Override
- public boolean isStateful() {
- return mClippedMatrixState.mDrawable.isStateful();
- }
-
- @Override
- protected boolean onStateChange(int[] state) {
- return mClippedMatrixState.mDrawable.setState(state);
- }
-
- @Override
- protected boolean onLevelChange(int level) {
- mClippedMatrixState.mDrawable.setLevel(level);
- invalidateSelf();
- return true;
- }
-
- @Override
- protected void onBoundsChange(Rect bounds) {
- super.setBounds(bounds);
- if (mClippedMatrixState.mMatrix == null) {
- mClippedMatrixState.mDrawable.setBounds(bounds);
- } else {
- int drawableWidth = mClippedMatrixState.mDrawable.getIntrinsicWidth();
- int drawableHeight = mClippedMatrixState.mDrawable.getIntrinsicHeight();
- mClippedMatrixState.mDrawable.setBounds(bounds.left, bounds.top,
- drawableWidth + bounds.left, drawableHeight + bounds.top);
- }
- invalidateSelf();
- }
-
- @Override
- public void draw(Canvas canvas) {
- Rect bounds = getBounds();
- int left = bounds.left;
- int top = bounds.top;
- int saveCount = canvas.getSaveCount();
- canvas.save();
- if (mClippedMatrixState.mClipRect != null) {
- canvas.clipRect(mClippedMatrixState.mClipRect);
- } else {
- canvas.clipRect(bounds);
- }
-
- if (mClippedMatrixState != null && !mClippedMatrixState.mMatrix.isIdentity()) {
- canvas.translate(left, top);
- canvas.concat(mClippedMatrixState.mMatrix);
- canvas.translate(-left, -top);
- }
- mClippedMatrixState.mDrawable.draw(canvas);
- canvas.restoreToCount(saveCount);
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mClippedMatrixState.mDrawable.getIntrinsicWidth();
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mClippedMatrixState.mDrawable.getIntrinsicHeight();
- }
-
- @Override
- public Drawable.ConstantState getConstantState() {
- if (mClippedMatrixState.canConstantState()) {
- mClippedMatrixState.mChangingConfigurations = getChangingConfigurations();
- return mClippedMatrixState;
- }
- return null;
- }
-
- final static class ClippedMatrixState extends Drawable.ConstantState {
- Drawable mDrawable;
- Matrix mMatrix;
- Rect mClipRect;
-
- private boolean mCheckedConstantState;
- private boolean mCanConstantState;
- int mChangingConfigurations;
-
- ClippedMatrixState(ClippedMatrixState orig, MatrixClippedDrawable owner, Resources res) {
- if (orig != null) {
- if (res != null) {
- mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
- } else {
- mDrawable = orig.mDrawable.getConstantState().newDrawable();
- }
- mDrawable.setCallback(owner);
- mCheckedConstantState = mCanConstantState = true;
- if (orig.mMatrix != null) {
- mMatrix = new Matrix(orig.mMatrix);
- }
- if (orig.mClipRect != null) {
- mClipRect = new Rect(orig.mClipRect);
- }
- }
- }
-
- @Override
- public Drawable newDrawable() {
- return new MatrixClippedDrawable(this, null);
- }
-
- @Override
- public Drawable newDrawable(Resources res) {
- return new MatrixClippedDrawable(this, res);
- }
-
- @Override
- public int getChangingConfigurations() {
- return mChangingConfigurations;
- }
-
- boolean canConstantState() {
- if (!mCheckedConstantState) {
- mCanConstantState = mDrawable.getConstantState() != null;
- mCheckedConstantState = true;
- }
-
- return mCanConstantState;
- }
- }
-
- private MatrixClippedDrawable(ClippedMatrixState state, Resources res) {
- mClippedMatrixState = new ClippedMatrixState(state, this, res);
- }
-
-}
diff --git a/core/java/android/transition/MoveImage.java b/core/java/android/transition/MoveImage.java
index 6f1b6f7..48b96ec 100644
--- a/core/java/android/transition/MoveImage.java
+++ b/core/java/android/transition/MoveImage.java
@@ -15,340 +15,17 @@
*/
package android.transition;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.RectEvaluator;
-import android.animation.TypeEvaluator;
-import android.animation.ValueAnimator;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.util.FloatMath;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroupOverlay;
-import android.view.ViewParent;
-import android.widget.ImageView;
-
-import java.util.ArrayList;
-import java.util.Map;
-
/**
- * Transitions ImageViews, including size, scaleType, and matrix. The ImageView drawable
- * must remain the same between both start and end states, but the
- * {@link ImageView#setScaleType(android.widget.ImageView.ScaleType)} may
- * differ.
+ * TO BE REMOVED.
+ * Use ChangeImageTransform + ChangeBounds instead.
+ * @hide
*/
-public class MoveImage extends Transition {
- private static final String TAG = "MoveImage";
- private static final String PROPNAME_MATRIX = "android:moveImage:matrix";
- private static final String PROPNAME_BOUNDS = "android:moveImage:bounds";
- private static final String PROPNAME_CLIP = "android:moveImage:clip";
- private static final String PROPNAME_DRAWABLE = "android:moveImage:drawable";
-
- private int[] mTempLoc = new int[2];
-
- private static final String[] sTransitionProperties = {
- PROPNAME_MATRIX,
- PROPNAME_BOUNDS,
- PROPNAME_CLIP,
- PROPNAME_DRAWABLE,
- };
-
- private void captureValues(TransitionValues transitionValues) {
- View view = transitionValues.view;
- if (!(view instanceof ImageView) || view.getVisibility() != View.VISIBLE) {
- return;
- }
- ImageView imageView = (ImageView) view;
- Drawable drawable = imageView.getDrawable();
- if (drawable == null) {
- return;
- }
- Map<String, Object> values = transitionValues.values;
- values.put(PROPNAME_DRAWABLE, drawable);
-
- ViewGroup parent = (ViewGroup) view.getParent();
- parent.getLocationInWindow(mTempLoc);
- int paddingLeft = view.getPaddingLeft();
- int paddingTop = view.getPaddingTop();
- int paddingRight = view.getPaddingRight();
- int paddingBottom = view.getPaddingBottom();
- int left = mTempLoc[0] + paddingLeft + view.getLeft() + Math.round(view.getTranslationX());
- int top = mTempLoc[1] + paddingTop + view.getTop() + Math.round(view.getTranslationY());
- int right = left + view.getWidth() - paddingRight - paddingLeft;
- int bottom = top + view.getHeight() - paddingTop - paddingBottom;
-
- Rect bounds = new Rect(left, top, right, bottom);
- values.put(PROPNAME_BOUNDS, bounds);
- Matrix matrix = getMatrix(imageView);
- values.put(PROPNAME_MATRIX, matrix);
- values.put(PROPNAME_CLIP, findClip(imageView));
- }
-
- @Override
- public void captureStartValues(TransitionValues transitionValues) {
- captureValues(transitionValues);
- }
-
- @Override
- public void captureEndValues(TransitionValues transitionValues) {
- captureValues(transitionValues);
- }
-
- @Override
- public String[] getTransitionProperties() {
- return sTransitionProperties;
- }
-
- /**
- * Creates an Animator for ImageViews moving, changing dimensions, and/or changing
- * {@link android.widget.ImageView.ScaleType}.
- * @param sceneRoot The root of the transition hierarchy.
- * @param startValues The values for a specific target in the start scene.
- * @param endValues The values for the target in the end scene.
- * @return An Animator to move an ImageView or null if the View is not an ImageView,
- * the Drawable changed, the View is not VISIBLE, or there was no change.
- */
- @Override
- public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
- TransitionValues endValues) {
- if (startValues == null || endValues == null
- || startValues.values.get(PROPNAME_BOUNDS) == null
- || endValues.values.get(PROPNAME_BOUNDS) == null
- || startValues.values.get(PROPNAME_DRAWABLE)
- != endValues.values.get(PROPNAME_DRAWABLE)) {
- return null;
- }
- ArrayList<PropertyValuesHolder> changes = new ArrayList<PropertyValuesHolder>();
-
- Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
- Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
-
- if (startMatrix != null && !startMatrix.equals(endMatrix)) {
- changes.add(PropertyValuesHolder.ofObject(MatrixClippedDrawable.MATRIX_PROPERTY,
- new MatrixEvaluator(), startMatrix, endMatrix));
- }
-
- sceneRoot.getLocationInWindow(mTempLoc);
- int rootX = mTempLoc[0];
- int rootY = mTempLoc[1];
- final ImageView imageView = (ImageView) endValues.view;
-
- Drawable drawable = imageView.getDrawable();
-
- Rect startBounds = new Rect((Rect) startValues.values.get(PROPNAME_BOUNDS));
- Rect endBounds = new Rect((Rect) endValues.values.get(PROPNAME_BOUNDS));
- startBounds.offset(-rootX, -rootY);
- endBounds.offset(-rootX, -rootY);
-
- if (!startBounds.equals(endBounds)) {
- changes.add(PropertyValuesHolder.ofObject("bounds", new RectEvaluator(new Rect()),
- startBounds, endBounds));
- }
-
- Rect startClip = (Rect) startValues.values.get(PROPNAME_CLIP);
- Rect endClip = (Rect) endValues.values.get(PROPNAME_CLIP);
- if (startClip != null || endClip != null) {
- startClip = nonNullClip(startClip, sceneRoot, rootX, rootY);
- endClip = nonNullClip(endClip, sceneRoot, rootX, rootY);
-
- expandClip(startBounds, startMatrix, startClip, endClip);
- expandClip(endBounds, endMatrix, endClip, startClip);
- boolean clipped = !startClip.contains(startBounds) || !endClip.contains(endBounds);
- if (!clipped) {
- startClip = null;
- } else if (!startClip.equals(endClip)) {
- changes.add(PropertyValuesHolder.ofObject(MatrixClippedDrawable.CLIP_PROPERTY,
- new RectEvaluator(), startClip, endClip));
- }
- }
-
- if (changes.isEmpty()) {
- return null;
- }
-
- drawable = drawable.getConstantState().newDrawable();
- final MatrixClippedDrawable matrixClippedDrawable = new MatrixClippedDrawable(drawable);
- final ImageView overlayImage = new ImageView(imageView.getContext());
- final ViewGroupOverlay overlay = sceneRoot.getOverlay();
- overlay.add(overlayImage);
- overlayImage.setLeft(0);
- overlayImage.setTop(0);
- overlayImage.setRight(sceneRoot.getWidth());
- overlayImage.setBottom(sceneRoot.getBottom());
- overlayImage.setScaleType(ImageView.ScaleType.MATRIX);
- overlayImage.setImageDrawable(matrixClippedDrawable);
- matrixClippedDrawable.setMatrix(startMatrix);
- matrixClippedDrawable.setBounds(startBounds);
- matrixClippedDrawable.setClipRect(startClip);
-
- imageView.setVisibility(View.INVISIBLE);
- ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(matrixClippedDrawable,
- changes.toArray(new PropertyValuesHolder[changes.size()]));
-
- AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- imageView.setVisibility(View.VISIBLE);
- overlay.remove(overlayImage);
- }
-
- @Override
- public void onAnimationPause(Animator animation) {
- imageView.setVisibility(View.VISIBLE);
- overlayImage.setVisibility(View.INVISIBLE);
- }
-
- @Override
- public void onAnimationResume(Animator animation) {
- imageView.setVisibility(View.INVISIBLE);
- overlayImage.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- onAnimationEnd(animation);
- }
- };
-
- animator.addListener(listener);
- animator.addPauseListener(listener);
-
- return animator;
- }
-
- private static Rect nonNullClip(Rect clip, ViewGroup sceneRoot, int rootX, int rootY) {
- if (clip != null) {
- clip = new Rect(clip);
- clip.offset(-rootX, -rootY);
- } else {
- clip = new Rect(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
- }
- return clip;
- }
-
- private static void expandClip(Rect bounds, Matrix matrix, Rect clip, Rect otherClip) {
- RectF boundsF = new RectF(bounds);
- if (matrix != null) {
- matrix.mapRect(boundsF);
- }
- clip.left = expandMinDimension(boundsF.left, clip.left, otherClip.left);
- clip.top = expandMinDimension(boundsF.top, clip.top, otherClip.top);
- clip.right = expandMaxDimension(boundsF.right, clip.right, otherClip.right);
- clip.bottom = expandMaxDimension(boundsF.bottom, clip.bottom, otherClip.bottom);
- }
-
- private static int expandMinDimension(float boundsDimension, int clipDimension,
- int otherClipDimension) {
- if (clipDimension > boundsDimension) {
- // Already clipped in that dimension, return the clipped value
- return clipDimension;
- }
- return Math.min(clipDimension, otherClipDimension);
- }
-
- private static int expandMaxDimension(float boundsDimension, int clipDimension,
- int otherClipDimension) {
- return -expandMinDimension(-boundsDimension, -clipDimension, -otherClipDimension);
- }
-
- private static Matrix getMatrix(ImageView imageView) {
- Drawable drawable = imageView.getDrawable();
- int drawableWidth = drawable.getIntrinsicWidth();
- int drawableHeight = drawable.getIntrinsicHeight();
- ImageView.ScaleType scaleType = imageView.getScaleType();
- Matrix matrix;
- if (drawableWidth <= 0 || drawableHeight <= 0) {
- matrix = null;
- } else if (scaleType == ImageView.ScaleType.FIT_XY) {
- matrix = new Matrix();
- float scaleX = imageView.getWidth();
- scaleX /= drawableWidth;
- float scaleY = imageView.getHeight();
- scaleY /= drawableHeight;
- matrix.setScale(scaleX, scaleY);
- } else {
- matrix = new Matrix(imageView.getImageMatrix());
- }
- return matrix;
- }
-
- private Rect findClip(ImageView imageView) {
- if (imageView.getCropToPadding()) {
- Rect clip = getClip(imageView);
- clip.left += imageView.getPaddingLeft();
- clip.right -= imageView.getPaddingRight();
- clip.top += imageView.getPaddingTop();
- clip.bottom -= imageView.getPaddingBottom();
- return clip;
- } else {
- View view = imageView;
- ViewParent viewParent;
- while ((viewParent = view.getParent()) instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) viewParent;
- if (viewGroup.getClipChildren()) {
- Rect clip = getClip(view);
- return clip;
- }
- view = viewGroup;
- }
- }
- return null;
- }
-
- private Rect getClip(View clipView) {
- Rect clipBounds = clipView.getClipBounds();
- if (clipBounds == null) {
- clipBounds = new Rect(clipView.getLeft(), clipView.getTop(),
- clipView.getRight(), clipView.getBottom());
- }
-
- ViewParent parent = clipView.getParent();
- if (parent instanceof ViewGroup) {
- ViewGroup parentViewGroup = (ViewGroup) parent;
- parentViewGroup.getLocationInWindow(mTempLoc);
- clipBounds.offset(mTempLoc[0], mTempLoc[1]);
- }
-
- return clipBounds;
- }
-
- @Override
- public Transition clone() {
- MoveImage clone = (MoveImage) super.clone();
- clone.mTempLoc = new int[2];
- return clone;
- }
-
- private static class MatrixEvaluator implements TypeEvaluator<Matrix> {
- static final Matrix sIdentity = new Matrix();
- float[] mTempStartValues = new float[9];
- float[] mTempEndValues = new float[9];
- Matrix mTempMatrix = new Matrix();
+public class MoveImage extends TransitionSet {
- @Override
- public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
- if (startValue == null && endValue == null) {
- return null;
- }
- if (startValue == null) {
- startValue = sIdentity;
- } else if (endValue == null) {
- endValue = sIdentity;
- }
- startValue.getValues(mTempStartValues);
- endValue.getValues(mTempEndValues);
- for (int i = 0; i < 9; i++) {
- float diff = mTempEndValues[i] - mTempStartValues[i];
- mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
- }
- mTempMatrix.setValues(mTempEndValues);
- return mTempMatrix;
- }
+ public MoveImage() {
+ addTransition(new ChangeBounds());
+ addTransition(new ChangeClipBounds());
+ addTransition(new ChangeTransform());
+ addTransition(new ChangeImageTransform());
}
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 0017eb1..988d23d 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -68,8 +68,8 @@ import java.util.List;
*
* <p>This TransitionSet contains {@link android.transition.Explode} for visibility,
* {@link android.transition.ChangeBounds}, {@link android.transition.ChangeTransform},
- * and {@link android.transition.ChangeClipBounds} for non-<code>ImageView</code>s and
- * {@link android.transition.MoveImage} for <code>ImageView</code>s:</p>
+ * and {@link android.transition.ChangeClipBounds} and
+ * {@link android.transition.ChangeImageTransform}:</p>
*
* {@sample development/samples/ApiDemos/res/transition/explode_move_together.xml MultipleTransform}
*
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 551f78c..1624188 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -158,6 +158,9 @@ public class TransitionInflater {
} else if ("moveImage".equals(name)) {
transition = new MoveImage();
newTransition = true;
+ } else if ("changeImageTransform".equals(name)) {
+ transition = new ChangeImageTransform();
+ newTransition = true;
} else if ("changeTransform".equals(name)) {
transition = new ChangeTransform();
newTransition = true;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0120875..0a44d23 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1435,7 +1435,7 @@ public abstract class Window {
/**
* Sets the Transition that will be used for shared elements transferred into the content
* Scene. Typical Transitions will affect size and location, such as
- * {@link android.transition.MoveImage} and {@link android.transition.ChangeBounds}. A null
+ * {@link android.transition.ChangeBounds}. A null
* value will cause transferred shared elements to blink to the final position.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
* @param transition The Transition to use for shared elements transferred into the content
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 5d578ca..e97177d 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1117,6 +1117,20 @@ public class ImageView extends View {
}
}
+ /** @hide */
+ public void animateTransform(Matrix matrix) {
+ if (matrix == null) {
+ mDrawable.setBounds(0, 0, getWidth(), getHeight());
+ } else {
+ mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight);
+ if (mDrawMatrix == null) {
+ mDrawMatrix = new Matrix();
+ }
+ mDrawMatrix.set(matrix);
+ }
+ invalidate();
+ }
+
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
diff --git a/core/res/res/transition/move.xml b/core/res/res/transition/move.xml
index d4863ee..56e1938 100644
--- a/core/res/res/transition/move.xml
+++ b/core/res/res/transition/move.xml
@@ -14,17 +14,8 @@
limitations under the License.
-->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
- <transitionSet>
- <changeBounds/>
- <changeTransform/>
- <changeClipBounds/>
- <targets>
- <target android:excludeClass="android.widget.ImageView"/>
- </targets>
- </transitionSet>
- <moveImage>
- <targets>
- <target android:targetClass="android.widget.ImageView"/>
- </targets>
- </moveImage>
+ <changeBounds/>
+ <changeTransform/>
+ <changeClipBounds/>
+ <changeImageTransform/>
</transitionSet>