diff options
author | George Mount <mount@google.com> | 2014-06-24 09:36:18 -0700 |
---|---|---|
committer | George Mount <mount@google.com> | 2014-06-25 13:45:16 -0700 |
commit | 990205eada00ad3e575761d19607bb03e12f9aa3 (patch) | |
tree | 5e3158f1ee3d41334f7e2830ae4df3eee3c0577e /core/java | |
parent | 16ffa8d3ef3d0a45efbca9fa7b4b32ba4ebd1e07 (diff) | |
download | frameworks_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
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/transition/ChangeImageTransform.java | 234 | ||||
-rw-r--r-- | core/java/android/transition/MatrixClippedDrawable.java | 300 | ||||
-rw-r--r-- | core/java/android/transition/MoveImage.java | 341 | ||||
-rw-r--r-- | core/java/android/transition/Transition.java | 4 | ||||
-rw-r--r-- | core/java/android/transition/TransitionInflater.java | 3 | ||||
-rw-r--r-- | core/java/android/view/Window.java | 2 | ||||
-rw-r--r-- | core/java/android/widget/ImageView.java | 14 |
7 files changed, 263 insertions, 635 deletions
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); |