Loading core/java/android/transition/Explode.java +34 −95 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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]; Loading @@ -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)); Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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); } } } core/java/android/transition/Slide.java +51 −91 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); } }; Loading @@ -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}. Loading @@ -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); } } core/java/android/transition/TranslationAnimationCreator.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * 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); } } } core/res/res/values/ids.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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> core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading Loading
core/java/android/transition/Explode.java +34 −95 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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]; Loading @@ -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)); Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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); } } }
core/java/android/transition/Slide.java +51 −91 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); } }; Loading @@ -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}. Loading @@ -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); } }
core/java/android/transition/TranslationAnimationCreator.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * 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); } } }
core/res/res/values/ids.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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>
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading