OSDN Git Service

Add ImageView-specific shared element activity transition code.
authorGeorge Mount <mount@google.com>
Mon, 5 May 2014 17:47:00 +0000 (10:47 -0700)
committerGeorge Mount <mount@google.com>
Mon, 5 May 2014 19:25:43 +0000 (12:25 -0700)
Bug 14497858

Probably more than 50% of shared elements will be ImageViews and
sharing the scale type and matrix between the two Activities will
simplify shared element transitions.

Also fixed MoveImage, which had a bug when the scale type was FIX_XY.

Change-Id: Ic5548b4d1420ced12507c18edf76c9e50e27a929

core/java/android/app/ActivityTransitionCoordinator.java
core/java/android/transition/MoveImage.java

index 3c1455b..3eb2fea 100644 (file)
@@ -21,6 +21,7 @@ import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,6 +31,7 @@ import android.transition.TransitionManager;
 import android.transition.TransitionSet;
 import android.util.ArrayMap;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroupOverlay;
@@ -138,6 +140,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
     private static final String KEY_HEIGHT = "shared_element:height";
     private static final String KEY_NAME = "shared_element:name";
     private static final String KEY_BITMAP = "shared_element:bitmap";
+    private static final String KEY_SCALE_TYPE = "shared_element:scaleType";
+    private static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
+
+    private static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
 
     /**
      * Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -322,7 +328,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
         final ArrayList<View> accepted = new ArrayList<View>();
         final ArrayList<View> rejected = new ArrayList<View>();
         createSharedElementImages(accepted, rejected, sharedElementNames, state);
-        setSharedElementState(state, accepted);
+        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
+                setSharedElementState(state, accepted);
         handleRejected(rejected);
 
         if (getViewsTransition() != null) {
@@ -331,6 +338,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
         setViewVisibility(mSharedElements, View.VISIBLE);
         Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
                 true);
+        setOriginalImageViewState(originalImageViewState);
 
         if (allowOverlappingTransitions()) {
             onStartEnterTransition(transition, mEnteringViews);
@@ -568,15 +576,22 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
         mEpicenterCallback.setEpicenter(epicenter);
     }
 
-    private void setSharedElementState(Bundle sharedElementState,
-            final ArrayList<View> acceptedOverlayViews) {
+    private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
+            Bundle sharedElementState, final ArrayList<View> acceptedOverlayViews) {
+        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
+                new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
         final int[] tempLoc = new int[2];
         if (sharedElementState != null) {
             for (int i = 0; i < mSharedElements.size(); i++) {
                 View sharedElement = mSharedElements.get(i);
+                String name = mTargetSharedNames.get(i);
+                Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
+                        name, sharedElementState);
+                if (originalState != null) {
+                    originalImageState.put((ImageView) sharedElement, originalState);
+                }
                 View parent = (View) sharedElement.getParent();
                 parent.getLocationOnScreen(tempLoc);
-                String name = mTargetSharedNames.get(i);
                 setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
                 sharedElement.requestLayout();
             }
@@ -596,6 +611,29 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
                     }
                 }
         );
+        return originalImageState;
+    }
+
+    private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
+            Bundle transitionArgs) {
+        if (!(view instanceof ImageView)) {
+            return null;
+        }
+        Bundle bundle = transitionArgs.getBundle(name);
+        int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
+        if (scaleTypeInt < 0) {
+            return null;
+        }
+
+        ImageView imageView = (ImageView) view;
+        ImageView.ScaleType originalScaleType = imageView.getScaleType();
+
+        Matrix originalMatrix = null;
+        if (originalScaleType == ImageView.ScaleType.MATRIX) {
+            originalMatrix = new Matrix(imageView.getImageMatrix());
+        }
+
+        return Pair.create(originalScaleType, originalMatrix);
     }
 
     /**
@@ -614,6 +652,21 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
             return;
         }
 
+        if (view instanceof ImageView) {
+            int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
+            if (scaleTypeInt >= 0) {
+                ImageView imageView = (ImageView) view;
+                ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
+                imageView.setScaleType(scaleType);
+                if (scaleType == ImageView.ScaleType.MATRIX) {
+                    float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
+                    Matrix matrix = new Matrix();
+                    matrix.setValues(matrixValues);
+                    imageView.setImageMatrix(matrix);
+                }
+            }
+        }
+
         float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
         view.setTranslationZ(z);
 
@@ -666,6 +719,17 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
         view.draw(canvas);
         sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
 
+        if (view instanceof ImageView) {
+            ImageView imageView = (ImageView) view;
+            int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
+            sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
+            if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
+                float[] matrix = new float[9];
+                imageView.getImageMatrix().getValues(matrix);
+                sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
+            }
+        }
+
         transitionArgs.putBundle(name, sharedElementBundle);
     }
 
@@ -829,6 +893,25 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
         }
     }
 
+    private static void setOriginalImageViewState(
+            ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
+        for (int i = 0; i < originalState.size(); i++) {
+            ImageView imageView = originalState.keyAt(i);
+            Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
+            imageView.setScaleType(state.first);
+            imageView.setImageMatrix(state.second);
+        }
+    }
+
+    private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
+        for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
+            if (scaleType == SCALE_TYPE_VALUES[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
         private Rect mEpicenter;
 
index e4c3939..183cdd2 100644 (file)
@@ -125,7 +125,7 @@ public class MoveImage extends Transition {
         Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
         Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
 
-        if (!startMatrix.equals(endMatrix)) {
+        if (startMatrix != null && !startMatrix.equals(endMatrix)) {
             changes.add(PropertyValuesHolder.ofObject(MatrixClippedDrawable.MATRIX_PROPERTY,
                     new MatrixEvaluator(), startMatrix, endMatrix));
         }
@@ -230,7 +230,9 @@ public class MoveImage extends Transition {
 
     private static void expandClip(Rect bounds, Matrix matrix, Rect clip, Rect otherClip) {
         RectF boundsF = new RectF(bounds);
-        matrix.mapRect(boundsF);
+        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);
@@ -256,10 +258,20 @@ public class MoveImage extends Transition {
         int drawableWidth = drawable.getIntrinsicWidth();
         int drawableHeight = drawable.getIntrinsicHeight();
         ImageView.ScaleType scaleType = imageView.getScaleType();
-        if (drawableWidth <= 0 || drawableHeight <= 0 || scaleType == ImageView.ScaleType.FIT_XY) {
-            return null;
+        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 new Matrix(imageView.getImageMatrix());
+        return matrix;
     }
 
     private Rect findClip(ImageView imageView) {