Cross-Activity Scene transitions API demo.

Change-Id: Icd644902b61ca2f03f21045bfad3a758075fb7cc
This commit is contained in:
George Mount
2013-12-12 11:05:15 -08:00
parent a8d44d8dbd
commit 77dfe829d1
21 changed files with 1139 additions and 36 deletions

View File

@@ -0,0 +1,198 @@
/*
* Copyright (C) 2013 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 com.example.android.apis.animation;
import com.example.android.apis.R;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.RectEvaluator;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.Window;
import android.widget.ImageView;
import java.util.Random;
/**
*
*/
public class ActivityTransition extends Activity {
private static final String TAG = "ActivityTransition";
private static final String KEY_LEFT_ON_SCREEN = "ViewTransitionValues:left:";
private static final String KEY_TOP_ON_SCREEN = "ViewTransitionValues:top:";
private static final String KEY_WIDTH = "ViewTransitionValues:width:";
private static final String KEY_HEIGHT = "ViewTransitionValues:height:";
private static final String KEY_ID = "ViewTransitionValues:id";
private Random mRandom = new Random();
private boolean mComeBack;
private Fall mFall;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setEarlyBackgroundTransition(false);
getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
setContentView(R.layout.image_block);
View hero = getHero();
if (hero != null) {
hero.setSharedElementName("hero");
}
TransitionManager transitionManager = getContentTransitionManager();
TransitionSet transitions = new TransitionSet();
Fall fall = new Fall();
fall.setDuration(600);
fall.setStartDelay(600);
fall.setHero(hero);
transitions.addTransition(fall);
transitions.addTransition(new Up());
transitionManager.setTransition("null", getContentScene(), transitions);
transitions = new TransitionSet();
mFall = new Fall();
mFall.setDuration(600);
transitions.addTransition(mFall);
transitions.addTransition(new Up());
transitionManager.setTransition(getContentScene(), "null", transitions);
}
@Override
protected void onResume() {
super.onResume();
if (mComeBack) {
mComeBack = false;
setContentView(R.layout.image_block);
}
}
private View getHero() {
Bundle transitionArgs = getTransitionArgs();
if (transitionArgs == null) {
return null;
}
int id = transitionArgs.getInt(KEY_ID);
return findViewById(id);
}
private static Property<Drawable, Rect> DRAWABLE_BOUNDS
= new Property<Drawable, Rect>(Rect.class, "bounds") {
@Override
public Rect get(Drawable object) {
return null;
}
@Override
public void set(Drawable object, Rect value) {
object.setBounds(value);
object.invalidateSelf();
}
};
@Override
public void startSharedElementTransition(Bundle transitionArgs) {
final ImageView hero = (ImageView)getHero();
hero.setSharedElementName(null);
hero.setVisibility(View.INVISIBLE);
int[] loc = new int[2];
hero.getLocationOnScreen(loc);
int endScreenLeft = loc[0];
int endScreenTop = loc[1];
int originalWidth = hero.getWidth();
int originalHeight = hero.getHeight();
hero.setVisibility(View.INVISIBLE);
ViewGroup sceneRoot = getContentScene().getSceneRoot();
sceneRoot.getLocationOnScreen(loc);
int overlayLeft = loc[0];
int overlayTop = loc[1];
final ViewGroupOverlay overlay = sceneRoot.getOverlay();
int endX = endScreenLeft - overlayLeft;
int endY = endScreenTop - overlayTop;
int startX = transitionArgs.getInt(KEY_LEFT_ON_SCREEN) - overlayLeft;
int startY = transitionArgs.getInt(KEY_TOP_ON_SCREEN) - overlayTop;
int startWidth = transitionArgs.getInt(KEY_WIDTH);
int startHeight = transitionArgs.getInt(KEY_HEIGHT);
int endHeight = originalWidth * startHeight / startWidth;
final Drawable image = hero.getDrawable();
Rect startBounds = new Rect(startX, startY, startX + startWidth, startY + startHeight);
endY += originalHeight - endHeight;
Rect endBounds = new Rect(endX, endY, endX + originalWidth, endY + endHeight);
ObjectAnimator boundsAnimator = ObjectAnimator.ofObject(image, DRAWABLE_BOUNDS,
new RectEvaluator(new Rect()), startBounds, endBounds);
hero.setImageDrawable(null);
image.setBounds(startBounds);
overlay.add(image);
boundsAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
overlay.remove(image);
hero.setImageDrawable(image);
hero.setVisibility(View.VISIBLE);
}
});
boundsAnimator.start();
}
public void clicked(View v) {
v.setSharedElementName("hero");
mFall.setHero(v);
Intent intent = new Intent(this, ActivityTransitionDetails.class);
Bundle args = getHeroInfo(v);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(args);
startActivity(intent, options.toBundle());
//v.setTranslationZ(300);
mComeBack = true;
}
private int randomColor() {
int red = mRandom.nextInt(128);
int green = mRandom.nextInt(128);
int blue = mRandom.nextInt(128);
return 0xFF000000 | (red << 16) | (green << 8) | blue;
}
static Bundle getHeroInfo(View view) {
int[] loc = new int[2];
view.getLocationOnScreen(loc);
Bundle bundle = new Bundle();
bundle.putInt(KEY_LEFT_ON_SCREEN, loc[0]);
bundle.putInt(KEY_TOP_ON_SCREEN, loc[1]);
bundle.putInt(KEY_WIDTH, view.getWidth());
bundle.putInt(KEY_HEIGHT, view.getHeight());
bundle.putInt(KEY_ID, view.getId());
return bundle;
}
}

View File

@@ -0,0 +1,240 @@
/*
* 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 com.example.android.apis.animation;
import com.example.android.apis.R;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.RectEvaluator;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.Log;
import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.ImageView;
import java.util.Random;
/**
*
*/
public class ActivityTransitionDetails extends Activity {
private static final String TAG = "ActivityTransitionDetails";
private static final String KEY_LEFT_ON_SCREEN = "ViewTransitionValues:left:";
private static final String KEY_TOP_ON_SCREEN = "ViewTransitionValues:top:";
private static final String KEY_WIDTH = "ViewTransitionValues:width:";
private static final String KEY_HEIGHT = "ViewTransitionValues:height:";
private static final String KEY_ID = "ViewTransitionValues:id";
private Random mRandom = new Random();
private boolean mComeBack;
private int mImageResourceId = R.drawable.ducky;
private int mId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setEarlyBackgroundTransition(false);
getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
setContentView(R.layout.image_details);
setImageMatrix();
ImageView hero = (ImageView)findViewById(R.id.titleImage);
hero.setImageDrawable(getHeroDrawable());
//hero.setTranslationZ(300);
TransitionManager transitionManager = getContentTransitionManager();
TransitionSet transitions = new TransitionSet();
Fall fall = new Fall();
fall.setDuration(600);
fall.setStartDelay(600);
transitions.addTransition(fall);
transitions.addTransition(new Up());
transitionManager.setTransition("null", getContentScene(), transitions);
transitions = new TransitionSet();
fall = new Fall();
fall.setDuration(600);
transitions.addTransition(fall);
transitions.addTransition(new Up());
transitionManager.setTransition(getContentScene(), "null", transitions);
}
@Override
protected void onResume() {
super.onResume();
if (mComeBack) {
mComeBack = false;
setContentView(R.layout.image_details);
ImageView hero = (ImageView)findViewById(R.id.titleImage);
hero.setImageDrawable(getHeroDrawable());
setImageMatrix();
}
}
private Drawable getHeroDrawable() {
Bundle args = getTransitionArgs();
int id = args == null ? 0 : args.getInt(KEY_ID);
int resourceId;
switch (id) {
case R.id.ducky: resourceId = R.drawable.ducky; break;
case R.id.jellies: resourceId = R.drawable.jellies; break;
case R.id.mug: resourceId = R.drawable.mug; break;
case R.id.pencil: resourceId = R.drawable.pencil; break;
case R.id.scissors: resourceId = R.drawable.scissors; break;
case R.id.woot: resourceId = R.drawable.woot; break;
case R.id.ball: resourceId = R.drawable.ball; break;
case R.id.block: resourceId = R.drawable.block; break;
default:
resourceId = mImageResourceId;
break;
}
mImageResourceId = resourceId;
return getResources().getDrawable(resourceId);
}
private static Property<Drawable, Rect> DRAWABLE_BOUNDS
= new Property<Drawable, Rect>(Rect.class, "bounds") {
@Override
public Rect get(Drawable object) {
return null;
}
@Override
public void set(Drawable object, Rect value) {
object.setBounds(value);
object.invalidateSelf();
}
};
private void setImageMatrix() {
getWindow().getDecorView().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this);
// Use an image matrix such that it aligns with the bottom.
final ImageView hero = (ImageView)findViewById(R.id.titleImage);
hero.setScaleType(ImageView.ScaleType.MATRIX);
Matrix matrix = hero.getImageMatrix();
int height = hero.getHeight();
int width = hero.getWidth();
Drawable image = hero.getDrawable();
int intrinsicHeight = image.getIntrinsicHeight();
int intrinsicWidth = image.getIntrinsicWidth();
int scaledHeight = intrinsicHeight * width / intrinsicWidth;
matrix.postTranslate(0, (height - scaledHeight) / 2);
hero.setImageMatrix(matrix);
return true;
}
});
}
@Override
public void startSharedElementTransition(Bundle transitionArgs) {
mId = transitionArgs.getInt(KEY_ID);
final ImageView hero = (ImageView)findViewById(R.id.titleImage);
int[] loc = new int[2];
hero.getLocationOnScreen(loc);
int endScreenLeft = loc[0];
int endScreenTop = loc[1];
int originalWidth = hero.getWidth();
int originalHeight = hero.getHeight();
hero.setVisibility(View.INVISIBLE);
ViewGroup sceneRoot = getContentScene().getSceneRoot();
sceneRoot.getLocationOnScreen(loc);
int overlayLeft = loc[0];
int overlayTop = loc[1];
final ViewGroupOverlay overlay = sceneRoot.getOverlay();
int endX = endScreenLeft - overlayLeft;
int endY = endScreenTop - overlayTop;
int startX = transitionArgs.getInt(KEY_LEFT_ON_SCREEN) - overlayLeft;
int startY = transitionArgs.getInt(KEY_TOP_ON_SCREEN) - overlayTop;
int startWidth = transitionArgs.getInt(KEY_WIDTH);
int startHeight = transitionArgs.getInt(KEY_HEIGHT);
int endHeight = originalWidth * startHeight / startWidth;
final Drawable image = hero.getDrawable();
Rect startBounds = new Rect(startX, startY, startX + startWidth, startY + startHeight);
endY += originalHeight - endHeight;
Rect endBounds = new Rect(endX, endY, endX + originalWidth, endY + endHeight);
ObjectAnimator boundsAnimator = ObjectAnimator.ofObject(image, DRAWABLE_BOUNDS,
new RectEvaluator(new Rect()), startBounds, endBounds);
hero.setImageDrawable(null);
image.setBounds(startBounds);
overlay.add(image);
boundsAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
overlay.remove(image);
hero.setImageDrawable(image);
hero.setVisibility(View.VISIBLE);
}
});
boundsAnimator.start();
}
public void clicked(View v) {
Intent intent = new Intent(this, ActivityTransition.class);
Bundle args = getHeroInfo((ImageView)v);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(args);
startActivity(intent, options.toBundle());
mComeBack = true;
}
private int randomColor() {
int red = mRandom.nextInt(128);
int green = mRandom.nextInt(128);
int blue = mRandom.nextInt(128);
return 0xFF000000 | (red << 16) | (green << 8) | blue;
}
private Bundle getHeroInfo(ImageView view) {
int[] loc = new int[2];
view.getLocationOnScreen(loc);
Bundle bundle = new Bundle();
Drawable image = view.getDrawable();
int intrinsicWidth = image.getIntrinsicWidth();
int intrinsicHeight = image.getIntrinsicHeight();
int width = view.getWidth();
int height = intrinsicHeight * width / intrinsicWidth;
int top = loc[1] + view.getHeight() - height;
bundle.putInt(KEY_LEFT_ON_SCREEN, loc[0]);
bundle.putInt(KEY_TOP_ON_SCREEN, top);
bundle.putInt(KEY_WIDTH, width);
bundle.putInt(KEY_HEIGHT, height);
bundle.putInt(KEY_ID, mId);
return bundle;
}
}

View File

@@ -0,0 +1,335 @@
/*
* 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 com.example.android.apis.animation;
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.transition.Transition;
import android.transition.TransitionValues;
import android.transition.Visibility;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
/**
*
*/
public class Fall extends Visibility {
private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
private static final String TAG = "Fall";
private static final String PROPNAME_SCREEN_LOCATION = "android:fade:screen_location";
private View mHero;
public void setHero(View hero) {
mHero = hero;
}
private Animator createAnimation(final View view, long startDelay, final float startY,
float endY, AnimatorListenerAdapter listener, TimeInterpolator interpolator) {
if (startY == endY) {
// run listener if we're noop'ing the animation, to get the end-state results now
if (listener != null) {
listener.onAnimationEnd(null);
}
return null;
}
final ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
if (listener != null) {
anim.addListener(listener);
anim.addPauseListener(listener);
}
anim.setInterpolator(interpolator);
anim.setStartDelay(startDelay);
AnimatorSet wrapper = new AnimatorSet();
wrapper.play(anim);
wrapper.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
view.setTranslationY(startY);
}
});
return wrapper;
}
private void captureValues(TransitionValues transitionValues) {
int[] loc = new int[2];
transitionValues.view.getLocationOnScreen(loc);
transitionValues.values.put(PROPNAME_SCREEN_LOCATION, loc);
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
super.captureStartValues(transitionValues);
captureValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
super.captureEndValues(transitionValues);
captureValues(transitionValues);
}
@Override
public Animator onAppear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
if (endValues == null) {
return null;
}
final View endView = endValues.view;
Log.v(TAG, "onAppear: " + endView.getId());
final float endY = endView.getTranslationY();
final float startY = endY + sceneRoot.getHeight();
TransitionListener transitionListener = new TransitionListener() {
boolean mCanceled = false;
float mPausedY;
@Override
public void onTransitionCancel(Transition transition) {
endView.setTranslationY(endY);
mCanceled = true;
}
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
if (!mCanceled) {
endView.setTranslationY(endY);
}
}
@Override
public void onTransitionPause(Transition transition) {
mPausedY = endView.getTranslationY();
endView.setTranslationY(endY);
}
@Override
public void onTransitionResume(Transition transition) {
endView.setTranslationY(mPausedY);
}
};
addListener(transitionListener);
int[] loc = (int[]) endValues.values.get(PROPNAME_SCREEN_LOCATION);
long startDelay = calculateRiseStartDelay(sceneRoot, endView, loc);
return createAnimation(endView, startDelay, startY, endY, null, sDecelerate);
}
@Override
public Animator onDisappear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
View view = null;
View startView = (startValues != null) ? startValues.view : null;
View endView = (endValues != null) ? endValues.view : null;
View overlayView = null;
View viewToKeep = null;
if (endView == null || endView.getParent() == null) {
if (endView != null) {
// endView was removed from its parent - add it to the overlay
view = overlayView = endView;
} else if (startView != null) {
// endView does not exist. Use startView only under certain
// conditions, because placing a view in an overlay necessitates
// it being removed from its current parent
if (startView.getParent() == null) {
// no parent - safe to use
view = overlayView = startView;
} else if (startView.getParent() instanceof View &&
startView.getParent().getParent() == null) {
View startParent = (View) startView.getParent();
int id = startParent.getId();
if (id != View.NO_ID && sceneRoot.findViewById(id) != null && canRemoveViews()) {
// no parent, but its parent is unparented but the parent
// hierarchy has been replaced by a new hierarchy with the same id
// and it is safe to un-parent startView
view = overlayView = startView;
}
}
}
} else {
// visibility change
if (endVisibility == View.INVISIBLE) {
view = endView;
viewToKeep = view;
} else {
// Becoming GONE
if (startView == endView) {
view = endView;
viewToKeep = view;
} else {
view = startView;
overlayView = view;
}
}
}
final int finalVisibility = endVisibility;
int[] loc = (int[]) startValues.values.get(PROPNAME_SCREEN_LOCATION);
// TODO: add automatic facility to Visibility superclass for keeping views around
if (overlayView != null) {
// TODO: Need to do this for general case of adding to overlay
long startDelay = calculateFallStartDelay(sceneRoot, overlayView, loc);
int screenX = loc[0];
int screenY = loc[1];
loc = new int[2];
sceneRoot.getLocationOnScreen(loc);
overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
sceneRoot.getOverlay().add(overlayView);
// TODO: add automatic facility to Visibility superclass for keeping views around
final float startY = overlayView.getTranslationY();
float endY = startY + sceneRoot.getHeight();
final View finalView = view;
final View finalOverlayView = overlayView;
final View finalViewToKeep = viewToKeep;
final ViewGroup finalSceneRoot = sceneRoot;
final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
finalView.setTranslationY(startY);
// TODO: restore view offset from overlay repositioning
if (finalViewToKeep != null) {
finalViewToKeep.setVisibility(finalVisibility);
}
if (finalOverlayView != null) {
finalSceneRoot.getOverlay().remove(finalOverlayView);
}
}
@Override
public void onAnimationPause(Animator animation) {
if (finalOverlayView != null) {
finalSceneRoot.getOverlay().remove(finalOverlayView);
}
}
@Override
public void onAnimationResume(Animator animation) {
if (finalOverlayView != null) {
finalSceneRoot.getOverlay().add(finalOverlayView);
}
}
};
return createAnimation(view, startDelay, startY, endY, endListener, sAccelerate);
}
if (viewToKeep != null) {
long startDelay = calculateFallStartDelay(sceneRoot, viewToKeep, loc);
// TODO: find a different way to do this, like just changing the view to be
// VISIBLE for the duration of the transition
viewToKeep.setVisibility((View.VISIBLE));
// TODO: add automatic facility to Visibility superclass for keeping views around
final float startY = viewToKeep.getTranslationY();
float endY = startY + sceneRoot.getHeight();
final View finalView = view;
final View finalOverlayView = overlayView;
final View finalViewToKeep = viewToKeep;
final ViewGroup finalSceneRoot = sceneRoot;
final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
boolean mCanceled = false;
float mPausedY = -1;
@Override
public void onAnimationPause(Animator animation) {
if (finalViewToKeep != null && !mCanceled) {
finalViewToKeep.setVisibility(finalVisibility);
}
mPausedY = finalView.getTranslationY();
finalView.setTranslationY(startY);
}
@Override
public void onAnimationResume(Animator animation) {
if (finalViewToKeep != null && !mCanceled) {
finalViewToKeep.setVisibility(View.VISIBLE);
}
finalView.setTranslationY(mPausedY);
}
@Override
public void onAnimationCancel(Animator animation) {
mCanceled = true;
if (mPausedY >= 0) {
finalView.setTranslationY(mPausedY);
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mCanceled) {
finalView.setTranslationY(startY);
}
// TODO: restore view offset from overlay repositioning
if (finalViewToKeep != null && !mCanceled) {
finalViewToKeep.setVisibility(finalVisibility);
}
if (finalOverlayView != null) {
finalSceneRoot.getOverlay().remove(finalOverlayView);
}
}
};
return createAnimation(view, startDelay, startY, endY, endListener, sAccelerate);
}
return null;
}
private long calculateFallStartDelay(View sceneRoot, View view, int[] viewLoc) {
int[] loc = new int[2];
sceneRoot.getLocationOnScreen(loc);
int bottom = loc[1] + sceneRoot.getHeight();
float distance = bottom - viewLoc[1] + view.getTranslationY();
if (mHero != null) {
mHero.getLocationOnScreen(loc);
float heroX = loc[0] + mHero.getTranslationX() + (mHero.getWidth() / 2.0f);
float viewX = viewLoc[0] + view.getTranslationX() + (view.getWidth() / 2.0f);
float distanceX = Math.abs(heroX - viewX);
float distanceXRatio = distanceX / sceneRoot.getWidth();
distance += (1 - distanceXRatio) * mHero.getHeight();
}
float distanceRatio = distance/sceneRoot.getHeight() / 3;
return Math.max(0, Math.round(distanceRatio * getDuration()));
}
private long calculateRiseStartDelay(View sceneRoot, View view, int[] viewLoc) {
int[] loc = new int[2];
sceneRoot.getLocationOnScreen(loc);
int top = loc[1];
float distance = viewLoc[1] + view.getTranslationY() - top;
if (mHero != null) {
mHero.getLocationOnScreen(loc);
float heroX = loc[0] + mHero.getTranslationX() + (mHero.getWidth() / 2.0f);
float viewX = viewLoc[0] + view.getTranslationX() + (view.getWidth() / 2.0f);
float distanceX = Math.abs(heroX - viewX);
float distanceXRatio = distanceX / sceneRoot.getWidth();
distance += distanceXRatio * mHero.getHeight();
}
float distanceRatio = distance/sceneRoot.getHeight() / 3;
return Math.max(0, Math.round(distanceRatio * getDuration()));
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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 com.example.android.apis.animation;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.transition.Transition;
import android.transition.TransitionValues;
import android.view.View;
import android.view.ViewGroup;
/**
*
*/
public class Up extends Transition {
private static final String PROPNAME_Z = "android:z:height";
private static final String[] sTransitionProperties = {
PROPNAME_Z,
};
@Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
private void captureValues(TransitionValues transitionValues) {
View view = transitionValues.view;
transitionValues.values.put(PROPNAME_Z, view.getTranslationZ());
}
@Override
public String[] getTransitionProperties() {
return sTransitionProperties;
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
}
final float startZ = (Float)startValues.values.get(PROPNAME_Z);
final float endZ = (Float)endValues.values.get(PROPNAME_Z);
if (startZ == endZ) {
return null;
}
final View view = endValues.view;
TransitionListener transitionListener = new TransitionListener() {
boolean mCanceled = false;
float mPausedZ;
@Override
public void onTransitionCancel(Transition transition) {
view.setTranslationZ(endZ);
mCanceled = true;
}
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
if (!mCanceled) {
view.setTranslationZ(endZ);
}
}
@Override
public void onTransitionPause(Transition transition) {
mPausedZ = view.getTranslationZ();
view.setTranslationZ(endZ);
}
@Override
public void onTransitionResume(Transition transition) {
view.setTranslationZ(mPausedZ);
}
};
addListener(transitionListener);
return ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, startZ, endZ);
}
}