diff options
| -rw-r--r-- | core/java/android/transition/Explode.java | 129 | ||||
| -rw-r--r-- | core/java/android/transition/Slide.java | 142 | ||||
| -rw-r--r-- | core/java/android/transition/TranslationAnimationCreator.java | 139 | ||||
| -rw-r--r-- | core/res/res/values/ids.xml | 1 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 1 |
5 files changed, 226 insertions, 186 deletions
diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java index fae527c..feb8efd 100644 --- a/core/java/android/transition/Explode.java +++ b/core/java/android/transition/Explode.java @@ -15,20 +15,16 @@ */ package android.transition; +import com.android.internal.R; + import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; -import android.graphics.Path; import android.graphics.Rect; import android.util.FloatMath; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; - /** * This transition tracks changes to the visibility of target views in the * start and end scenes and moves views in or out from the edges of the @@ -44,8 +40,7 @@ public class Explode extends Visibility { private static final TimeInterpolator sDecelerate = new DecelerateInterpolator(); private static final TimeInterpolator sAccelerate = new AccelerateInterpolator(); private static final String TAG = "Explode"; - - private static final String PROPNAME_SCREEN_BOUNDS = "android:out:screenBounds"; + private static final String PROPNAME_SCREEN_BOUNDS = "android:explode:screenBounds"; private int[] mTempLoc = new int[2]; @@ -56,8 +51,8 @@ public class Explode extends Visibility { private void captureValues(TransitionValues transitionValues) { View view = transitionValues.view; view.getLocationOnScreen(mTempLoc); - int left = mTempLoc[0] + Math.round(view.getTranslationX()); - int top = mTempLoc[1] + Math.round(view.getTranslationY()); + int left = mTempLoc[0]; + int top = mTempLoc[1]; int right = left + view.getWidth(); int bottom = top + view.getHeight(); transitionValues.values.put(PROPNAME_SCREEN_BOUNDS, new Rect(left, top, right, bottom)); @@ -75,27 +70,6 @@ public class Explode extends Visibility { captureValues(transitionValues); } - private Animator createAnimation(final View view, float startX, float startY, float endX, - float endY, float terminalX, float terminalY, TimeInterpolator interpolator) { - view.setTranslationX(startX); - view.setTranslationY(startY); - if (startY == endY && startX == endX) { - return null; - } - Path path = new Path(); - path.moveTo(startX, startY); - path.lineTo(endX, endY); - ObjectAnimator pathAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, - View.TRANSLATION_Y, path); - pathAnimator.setInterpolator(interpolator); - OutAnimatorListener listener = new OutAnimatorListener(view, terminalX, terminalY, - endX, endY); - pathAnimator.addListener(listener); - pathAnimator.addPauseListener(listener); - - return pathAnimator; - } - @Override public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { @@ -103,29 +77,43 @@ public class Explode extends Visibility { return null; } Rect bounds = (Rect) endValues.values.get(PROPNAME_SCREEN_BOUNDS); + float endX = view.getTranslationX(); + float endY = view.getTranslationY(); calculateOut(sceneRoot, bounds, mTempLoc); + float startX = endX + mTempLoc[0]; + float startY = endY + mTempLoc[1]; - final float endX = view.getTranslationX(); - final float startX = endX + mTempLoc[0]; - final float endY = view.getTranslationY(); - final float startY = endY + mTempLoc[1]; - - return createAnimation(view, startX, startY, endX, endY, endX, endY, sDecelerate); + return TranslationAnimationCreator.createAnimation(view, endValues, bounds.left, bounds.top, + startX, startY, endX, endY, sDecelerate); } @Override public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { + if (startValues == null) { + return null; + } Rect bounds = (Rect) startValues.values.get(PROPNAME_SCREEN_BOUNDS); + int viewPosX = bounds.left; + int viewPosY = bounds.top; + float startX = view.getTranslationX(); + float startY = view.getTranslationY(); + float endX = startX; + float endY = startY; + int[] interruptedPosition = (int[]) startValues.view.getTag(R.id.transitionPosition); + if (interruptedPosition != null) { + // We want to have the end position relative to the interrupted position, not + // the position it was supposed to start at. + endX += interruptedPosition[0] - bounds.left; + endY += interruptedPosition[1] - bounds.top; + bounds.offsetTo(interruptedPosition[0], interruptedPosition[1]); + } calculateOut(sceneRoot, bounds, mTempLoc); + endX += mTempLoc[0]; + endY += mTempLoc[1]; - final float startX = view.getTranslationX(); - final float endX = startX + mTempLoc[0]; - final float startY = view.getTranslationY(); - final float endY = startY + mTempLoc[1]; - - return createAnimation(view, startX, startY, endX, endY, startX, startY, - sAccelerate); + return TranslationAnimationCreator.createAnimation(view, startValues, + viewPosX, viewPosY, startX, startY, endX, endY, sAccelerate); } private void calculateOut(View sceneRoot, Rect bounds, int[] outVector) { @@ -153,8 +141,8 @@ public class Explode extends Visibility { if (xVector == 0 && yVector == 0) { // Random direction when View is centered on focal View. - xVector = (float)(Math.random() * 2) - 1; - yVector = (float)(Math.random() * 2) - 1; + xVector = (float) (Math.random() * 2) - 1; + yVector = (float) (Math.random() * 2) - 1; } float vectorSize = calculateDistance(xVector, yVector); xVector /= vectorSize; @@ -176,53 +164,4 @@ public class Explode extends Visibility { private static float calculateDistance(float x, float y) { return FloatMath.sqrt((x * x) + (y * y)); } - - private static class OutAnimatorListener extends AnimatorListenerAdapter { - private final View mView; - private boolean mCanceled = false; - private float mPausedX; - private float mPausedY; - private final float mTerminalX; - private final float mTerminalY; - private final float mEndX; - private final float mEndY; - - public OutAnimatorListener(View view, float terminalX, float terminalY, - float endX, float endY) { - mView = view; - mTerminalX = terminalX; - mTerminalY = terminalY; - mEndX = endX; - mEndY = endY; - } - - @Override - public void onAnimationCancel(Animator animator) { - mView.setTranslationX(mTerminalX); - mView.setTranslationY(mTerminalY); - mCanceled = true; - } - - @Override - public void onAnimationEnd(Animator animator) { - if (!mCanceled) { - mView.setTranslationX(mTerminalX); - mView.setTranslationY(mTerminalY); - } - } - - @Override - public void onAnimationPause(Animator animator) { - mPausedX = mView.getTranslationX(); - mPausedY = mView.getTranslationY(); - mView.setTranslationY(mEndX); - mView.setTranslationY(mEndY); - } - - @Override - public void onAnimationResume(Animator animator) { - mView.setTranslationX(mPausedX); - mView.setTranslationY(mPausedY); - } - } } diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java index 8269258..0d2e487 100644 --- a/core/java/android/transition/Slide.java +++ b/core/java/android/transition/Slide.java @@ -16,14 +16,7 @@ package android.transition; import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; -import android.graphics.Rect; -import android.util.Log; -import android.util.Property; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -41,71 +34,60 @@ import android.view.animation.DecelerateInterpolator; */ public class Slide extends Visibility { private static final String TAG = "Slide"; - private static final TimeInterpolator sDecelerate = new DecelerateInterpolator(); private static final TimeInterpolator sAccelerate = new AccelerateInterpolator(); - + private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition"; private CalculateSlide mSlideCalculator = sCalculateBottom; private interface CalculateSlide { - /** Returns the translation value for view when it out of the scene */ - float getGone(ViewGroup sceneRoot, View view); - /** Returns the translation value for view when it is in the scene */ - float getHere(View view); + /** Returns the translation value for view when it goes out of the scene */ + float getGoneX(ViewGroup sceneRoot, View view); - /** Returns the property to animate translation */ - Property<View, Float> getProperty(); + /** Returns the translation value for view when it goes out of the scene */ + float getGoneY(ViewGroup sceneRoot, View view); } private static abstract class CalculateSlideHorizontal implements CalculateSlide { - @Override - public float getHere(View view) { - return view.getTranslationX(); - } @Override - public Property<View, Float> getProperty() { - return View.TRANSLATION_X; + public float getGoneY(ViewGroup sceneRoot, View view) { + return view.getTranslationY(); } } private static abstract class CalculateSlideVertical implements CalculateSlide { - @Override - public float getHere(View view) { - return view.getTranslationY(); - } @Override - public Property<View, Float> getProperty() { - return View.TRANSLATION_Y; + public float getGoneX(ViewGroup sceneRoot, View view) { + return view.getTranslationX(); } } private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() { @Override - public float getGone(ViewGroup sceneRoot, View view) { + public float getGoneX(ViewGroup sceneRoot, View view) { return view.getTranslationX() - sceneRoot.getWidth(); } }; private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() { @Override - public float getGone(ViewGroup sceneRoot, View view) { + public float getGoneY(ViewGroup sceneRoot, View view) { return view.getTranslationY() - sceneRoot.getHeight(); } }; private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() { @Override - public float getGone(ViewGroup sceneRoot, View view) { + public float getGoneX(ViewGroup sceneRoot, View view) { return view.getTranslationX() + sceneRoot.getWidth(); } }; private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() { @Override - public float getGone(ViewGroup sceneRoot, View view) { + public float getGoneY(ViewGroup sceneRoot, View view) { return view.getTranslationY() + sceneRoot.getHeight(); } }; @@ -125,8 +107,28 @@ public class Slide extends Visibility { setSlideEdge(slideEdge); } + private void captureValues(TransitionValues transitionValues) { + View view = transitionValues.view; + int[] position = new int[2]; + view.getLocationOnScreen(position); + transitionValues.values.put(PROPNAME_SCREEN_POSITION, position); + } + + @Override + public void captureStartValues(TransitionValues transitionValues) { + super.captureStartValues(transitionValues); + captureValues(transitionValues); + } + + @Override + public void captureEndValues(TransitionValues transitionValues) { + super.captureEndValues(transitionValues); + captureValues(transitionValues); + } + /** * Change the edge that Views appear and disappear from. + * * @param slideEdge The edge of the scene to use for Views appearing and disappearing. One of * {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP}, * {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM}. @@ -153,77 +155,35 @@ public class Slide extends Visibility { setPropagation(propagation); } - private Animator createAnimation(final View view, Property<View, Float> property, - float start, float end, float terminalValue, TimeInterpolator interpolator) { - view.setTranslationY(start); - if (start == end) { - return null; - } - final ObjectAnimator anim = ObjectAnimator.ofFloat(view, property, start, end); - - SlideAnimatorListener listener = new SlideAnimatorListener(view, terminalValue, end); - anim.addListener(listener); - anim.addPauseListener(listener); - anim.setInterpolator(interpolator); - return anim; - } - @Override public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { if (endValues == null) { return null; } - float end = mSlideCalculator.getHere(view); - float start = mSlideCalculator.getGone(sceneRoot, view); - return createAnimation(view, mSlideCalculator.getProperty(), start, end, end, sDecelerate); + int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION); + float endX = view.getTranslationX(); + float endY = view.getTranslationY(); + float startX = mSlideCalculator.getGoneX(sceneRoot, view); + float startY = mSlideCalculator.getGoneY(sceneRoot, view); + return TranslationAnimationCreator + .createAnimation(view, endValues, position[0], position[1], + startX, startY, endX, endY, sDecelerate); } @Override public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { - float start = mSlideCalculator.getHere(view); - float end = mSlideCalculator.getGone(sceneRoot, view); - - return createAnimation(view, mSlideCalculator.getProperty(), start, end, start, - sAccelerate); - } - - private static class SlideAnimatorListener extends AnimatorListenerAdapter { - private boolean mCanceled = false; - private float mPausedY; - private final View mView; - private final float mEndY; - private final float mTerminalY; - - public SlideAnimatorListener(View view, float terminalY, float endY) { - mView = view; - mTerminalY = terminalY; - mEndY = endY; - } - - @Override - public void onAnimationCancel(Animator animator) { - mView.setTranslationY(mTerminalY); - mCanceled = true; - } - - @Override - public void onAnimationEnd(Animator animator) { - if (!mCanceled) { - mView.setTranslationY(mTerminalY); - } - } - - @Override - public void onAnimationPause(Animator animator) { - mPausedY = mView.getTranslationY(); - mView.setTranslationY(mEndY); - } - - @Override - public void onAnimationResume(Animator animator) { - mView.setTranslationY(mPausedY); + if (startValues == null) { + return null; } + int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION); + float startX = view.getTranslationX(); + float startY = view.getTranslationY(); + float endX = mSlideCalculator.getGoneX(sceneRoot, view); + float endY = mSlideCalculator.getGoneY(sceneRoot, view); + return TranslationAnimationCreator + .createAnimation(view, startValues, position[0], position[1], + startX, startY, endX, endY, sAccelerate); } } diff --git a/core/java/android/transition/TranslationAnimationCreator.java b/core/java/android/transition/TranslationAnimationCreator.java new file mode 100644 index 0000000..de71fd7 --- /dev/null +++ b/core/java/android/transition/TranslationAnimationCreator.java @@ -0,0 +1,139 @@ +/* + * 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 com.android.internal.R; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; +import android.graphics.Path; +import android.view.View; + +/** + * This class is used by Slide and Explode to create an animator that goes from the start + * position to the end position. It takes into account the canceled position so that it + * will not blink out or shift suddenly when the transition is interrupted. + */ +class TranslationAnimationCreator { + + /** + * Creates an animator that can be used for x and/or y translations. When interrupted, + * it sets a tag to keep track of the position so that it may be continued from position. + * + * @param view The view being moved. This may be in the overlay for onDisappear. + * @param values The values containing the view in the view hierarchy. + * @param viewPosX The x screen coordinate of view + * @param viewPosY The y screen coordinate of view + * @param startX The start translation x of view + * @param startY The start translation y of view + * @param endX The end translation x of view + * @param endY The end translation y of view + * @param interpolator The interpolator to use with this animator. + * @return An animator that moves from (startX, startY) to (endX, endY) unless there was + * a previous interruption, in which case it moves from the current position to (endX, endY). + */ + static Animator createAnimation(View view, TransitionValues values, int viewPosX, int viewPosY, + float startX, float startY, float endX, float endY, TimeInterpolator interpolator) { + float terminalX = view.getTranslationX(); + float terminalY = view.getTranslationY(); + int[] startPosition = (int[]) values.view.getTag(R.id.transitionPosition); + if (startPosition != null) { + startX = startPosition[0] - viewPosX + terminalX; + startY = startPosition[1] - viewPosY + terminalY; + } + // Initial position is at translation startX, startY, so position is offset by that amount + int startPosX = viewPosX + Math.round(startX - terminalX); + int startPosY = viewPosY + Math.round(startY - terminalY); + + view.setTranslationX(startX); + view.setTranslationY(startY); + if (startX == endX && startY == endY) { + return null; + } + Path path = new Path(); + path.moveTo(startX, startY); + path.lineTo(endX, endY); + ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y, + path); + + TransitionPositionListener listener = new TransitionPositionListener(view, values.view, + startPosX, startPosY, terminalX, terminalY); + anim.addListener(listener); + anim.addPauseListener(listener); + anim.setInterpolator(interpolator); + return anim; + } + + private static class TransitionPositionListener extends AnimatorListenerAdapter { + + private final View mViewInHierarchy; + private final View mMovingView; + private final int mStartX; + private final int mStartY; + private int[] mTransitionPosition; + private float mPausedX; + private float mPausedY; + private final float mTerminalX; + private final float mTerminalY; + + private TransitionPositionListener(View movingView, View viewInHierarchy, + int startX, int startY, float terminalX, float terminalY) { + mMovingView = movingView; + mViewInHierarchy = viewInHierarchy; + mStartX = startX - Math.round(mMovingView.getTranslationX()); + mStartY = startY - Math.round(mMovingView.getTranslationY()); + mTerminalX = terminalX; + mTerminalY = terminalY; + mTransitionPosition = (int[]) mViewInHierarchy.getTag(R.id.transitionPosition); + if (mTransitionPosition != null) { + mViewInHierarchy.setTagInternal(R.id.transitionPosition, null); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + if (mTransitionPosition == null) { + mTransitionPosition = new int[2]; + } + mTransitionPosition[0] = Math.round(mStartX + mMovingView.getTranslationX()); + mTransitionPosition[1] = Math.round(mStartY + mMovingView.getTranslationY()); + mViewInHierarchy.setTagInternal(R.id.transitionPosition, mTransitionPosition); + } + + @Override + public void onAnimationEnd(Animator animator) { + mMovingView.setTranslationX(mTerminalX); + mMovingView.setTranslationY(mTerminalY); + } + + @Override + public void onAnimationPause(Animator animator) { + mPausedX = mMovingView.getTranslationX(); + mPausedY = mMovingView.getTranslationY(); + mMovingView.setTranslationX(mTerminalX); + mMovingView.setTranslationY(mTerminalY); + } + + @Override + public void onAnimationResume(Animator animator) { + mMovingView.setTranslationX(mPausedX); + mMovingView.setTranslationY(mPausedY); + } + } + +} diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 639091e..c64e910 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -84,4 +84,5 @@ <item type="id" name="current_scene" /> <item type="id" name="scene_layoutid_cache" /> <item type="id" name="mask" /> + <item type="id" name="transitionPosition" /> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 0436127..1547bbd 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -218,6 +218,7 @@ <java-symbol type="id" name="pin_error_message" /> <java-symbol type="id" name="timePickerLayout" /> <java-symbol type="id" name="profile_icon" /> + <java-symbol type="id" name="transitionPosition" /> <java-symbol type="attr" name="actionModeShareDrawable" /> <java-symbol type="attr" name="alertDialogCenterButtons" /> |
