From 4769ecc773ab09e5442cf4e37601a212a4126e42 Mon Sep 17 00:00:00 2001 From: George Mount Date: Wed, 26 Feb 2014 19:01:24 +0000 Subject: [PATCH] Support changes in Scene Activity Transition API redo. This reverts commit 1b3da3748f21532684cec68bbf59eb412c053bab. Change-Id: I84fd15c154a404ed10971025b7bb33f58a344965 --- samples/ApiDemos/AndroidManifest.xml | 10 +- samples/ApiDemos/res/layout/image_block.xml | 20 +- samples/ApiDemos/res/layout/image_details.xml | 39 +-- .../apis/animation/ActivityTransition.java | 171 ++++---------- .../animation/ActivityTransitionDetails.java | 223 ++++++------------ .../example/android/apis/animation/Fall.java | 73 ++++-- .../apis/animation/ScaleTransition.java | 87 +++++++ 7 files changed, 293 insertions(+), 330 deletions(-) create mode 100644 samples/ApiDemos/src/com/example/android/apis/animation/ScaleTransition.java diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml index 26fcbabe7..7e8c9e1eb 100644 --- a/samples/ApiDemos/AndroidManifest.xml +++ b/samples/ApiDemos/AndroidManifest.xml @@ -1295,8 +1295,8 @@ + android:enabled="@bool/atLeastHoneycomb" + android:theme="@style/ActivityTransitionTheme"> @@ -1304,9 +1304,9 @@ + android:label="Animation/Details of a specific thingy" + android:enabled="@bool/atLeastHoneycomb" + android:theme="@style/ActivityTransitionTheme"> diff --git a/samples/ApiDemos/res/layout/image_block.xml b/samples/ApiDemos/res/layout/image_block.xml index 50d7d049e..58d6a23d1 100644 --- a/samples/ApiDemos/res/layout/image_block.xml +++ b/samples/ApiDemos/res/layout/image_block.xml @@ -1,20 +1,21 @@ \ No newline at end of file diff --git a/samples/ApiDemos/res/layout/image_details.xml b/samples/ApiDemos/res/layout/image_details.xml index a1a745921..c58d70409 100644 --- a/samples/ApiDemos/res/layout/image_details.xml +++ b/samples/ApiDemos/res/layout/image_details.xml @@ -4,15 +4,22 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" + android:clipChildren="false" > - + + + @@ -30,7 +37,7 @@ android:layout_height="2dp" android:background="#808080"/> @@ -38,7 +45,7 @@ android:layout_height="2dp" android:background="#808080"/> @@ -46,7 +53,7 @@ android:layout_height="2dp" android:background="#808080"/> @@ -54,7 +61,7 @@ android:layout_height="2dp" android:background="#808080"/> @@ -62,7 +69,7 @@ android:layout_height="2dp" android:background="#808080"/> @@ -70,7 +77,7 @@ android:layout_height="2dp" android:background="#808080"/> @@ -78,7 +85,7 @@ android:layout_height="2dp" android:background="#808080"/> diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java index c3171c43e..2c8c0428c 100644 --- a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java +++ b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java @@ -17,23 +17,18 @@ 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.ChangeBounds; +import android.transition.Transition; import android.transition.TransitionManager; import android.transition.TransitionSet; -import android.util.Property; +import android.util.ArrayMap; +import android.util.Pair; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroupOverlay; import android.view.Window; import android.widget.ImageView; @@ -43,138 +38,52 @@ 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; + + private ImageView mHero; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS); - setEarlyBackgroundTransition(false); + getWindow().setTriggerEarlyEnterTransition(true); getWindow().setBackgroundDrawable(new ColorDrawable(randomColor())); setContentView(R.layout.image_block); - View hero = getHero(); - if (hero != null) { - hero.setSharedElementName("hero"); - } + setupHero(); 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 ScaleTransition()); + transitions.addTransition(new ChangeBounds()); 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); + transitionManager.setTransition(getContentScene(), transitions); + transitionManager.setExitTransition(getContentScene(), transitions); } - @Override - protected void onResume() { - super.onResume(); - if (mComeBack) { - mComeBack = false; - setContentView(R.layout.image_block); + private void setupHero() { + int id = getIntent().getIntExtra(KEY_ID, 0); + mHero = (ImageView) findViewById(id); + if (mHero != null) { + ArrayMap sharedElementsMap = new ArrayMap(); + sharedElementsMap.put("hero", mHero.getSharedElementName()); + getWindow().mapTransitionTargets(sharedElementsMap); } } - private View getHero() { - Bundle transitionArgs = getTransitionArgs(); - if (transitionArgs == null) { - return null; - } - int id = transitionArgs.getInt(KEY_ID); - return findViewById(id); - } - - private static Property DRAWABLE_BOUNDS - = new Property(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); + mHero = (ImageView) 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; + intent.putExtra(KEY_ID, v.getId()); + ActivityOptions activityOptions + = ActivityOptions.makeSceneTransitionAnimation(mHero, "hero"); + startActivity(intent, activityOptions.toBundle()); } private int randomColor() { @@ -184,15 +93,25 @@ public class ActivityTransition extends Activity { 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; + @Override + public void onCaptureSharedElementStart(Transition transition) { + int width = mHero.getWidth(); + int newTop = mHero.getBottom() - width; + mHero.setTop(newTop); + + int imageWidth = mHero.getDrawable().getIntrinsicWidth(); + mHero.setPivotX(0); + mHero.setPivotY(0); + float scale = ((float)width)/imageWidth; + mHero.setScaleX(scale); + mHero.setScaleY(scale); + } + + @Override + public void onCaptureSharedElementEnd() { + mHero.setPivotX(0); + mHero.setPivotY(0); + mHero.setScaleX(1); + mHero.setScaleY(1); } } diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java index d0b2c4f5a..2e40d9eb4 100644 --- a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java +++ b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java @@ -17,26 +17,18 @@ 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.ChangeBounds; +import android.transition.Transition; import android.transition.TransitionManager; import android.transition.TransitionSet; -import android.util.Log; -import android.util.Property; +import android.util.Pair; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroupOverlay; -import android.view.ViewTreeObserver; import android.view.Window; import android.widget.ImageView; @@ -46,72 +38,94 @@ 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; + + private int mId = R.id.ducky; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS); - setEarlyBackgroundTransition(false); + getWindow().setTriggerEarlyEnterTransition(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); + ImageView titleImage = (ImageView) findViewById(R.id.titleImage); + titleImage.setImageDrawable(getHeroDrawable()); + 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); + transitions.addTransition(new ChangeBounds()); + transitions.addTransition(new ScaleTransition()); + transitionManager.setTransition(getContentScene(), transitions); + transitionManager.setExitTransition(getContentScene(), 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(); - } + public void onCaptureSharedElementStart(Transition transition) { + ImageView imageView = (ImageView) findViewById(R.id.titleImage); + imageView.setScaleX(1); + imageView.setScaleY(1); + imageView.offsetTopAndBottom(-imageView.getTop()); + } + + @Override + public void onCaptureSharedElementEnd() { + setScale(); + } + + private void setScale() { + ImageView imageView = (ImageView) findViewById(R.id.titleImage); + Drawable drawable = imageView.getDrawable(); + float intrinsicWidth = drawable.getIntrinsicWidth(); + View sharedElementTarget = findViewById(R.id.shared_element); + float scale = sharedElementTarget.getWidth()/intrinsicWidth; + imageView.setPivotY(imageView.getHeight()); + imageView.setScaleX(scale); + imageView.setScaleY(scale); } private Drawable getHeroDrawable() { - Bundle args = getTransitionArgs(); - int id = args == null ? 0 : args.getInt(KEY_ID); + int id = getIntent().getIntExtra(KEY_ID, mId); + mId = 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; + 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; @@ -120,96 +134,11 @@ public class ActivityTransitionDetails extends Activity { return getResources().getDrawable(resourceId); } - private static Property DRAWABLE_BOUNDS - = new Property(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; + intent.putExtra(KEY_ID, mId); + ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(v, "hero"); + startActivity(intent, activityOptions.toBundle()); } private int randomColor() { @@ -219,22 +148,4 @@ public class ActivityTransitionDetails extends Activity { 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; - } - } diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/Fall.java b/samples/ApiDemos/src/com/example/android/apis/animation/Fall.java index e7281b383..6a866e572 100644 --- a/samples/ApiDemos/src/com/example/android/apis/animation/Fall.java +++ b/samples/ApiDemos/src/com/example/android/apis/animation/Fall.java @@ -20,11 +20,9 @@ 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; @@ -39,11 +37,7 @@ public class Fall extends Visibility { 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 View mFocusElement; private Animator createAnimation(final View view, long startDelay, final float startY, float endY, AnimatorListenerAdapter listener, TimeInterpolator interpolator) { @@ -99,7 +93,6 @@ public class Fall extends Visibility { return null; } final View endView = endValues.view; - Log.v(TAG, "onAppear: " + endView.getId()); final float endY = endView.getTranslationY(); final float startY = endY + sceneRoot.getHeight(); @@ -136,8 +129,9 @@ public class Fall extends Visibility { } }; addListener(transitionListener); + View sharedElement = getFocusElement(sceneRoot); int[] loc = (int[]) endValues.values.get(PROPNAME_SCREEN_LOCATION); - long startDelay = calculateRiseStartDelay(sceneRoot, endView, loc); + long startDelay = calculateRiseStartDelay(sceneRoot, sharedElement, endView, loc); return createAnimation(endView, startDelay, startY, endY, null, sDecelerate); } @@ -190,12 +184,13 @@ public class Fall extends Visibility { } } final int finalVisibility = endVisibility; + View sharedElement = getFocusElement(sceneRoot); 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); + long startDelay = calculateFallStartDelay(sceneRoot, sharedElement, overlayView, loc); int screenX = loc[0]; int screenY = loc[1]; loc = new int[2]; @@ -240,7 +235,7 @@ public class Fall extends Visibility { return createAnimation(view, startDelay, startY, endY, endListener, sAccelerate); } if (viewToKeep != null) { - long startDelay = calculateFallStartDelay(sceneRoot, viewToKeep, loc); + long startDelay = calculateFallStartDelay(sceneRoot, sharedElement, 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)); @@ -299,37 +294,73 @@ public class Fall extends Visibility { return null; } - private long calculateFallStartDelay(View sceneRoot, View view, int[] viewLoc) { + private View getFocusElement(ViewGroup sceneRoot) { + if (mFocusElement == null) { + mFocusElement = findFocusElement(sceneRoot); + if (mFocusElement == null) { + mFocusElement = sceneRoot; + } + } + return (mFocusElement == sceneRoot) ? null : mFocusElement; + } + + private static View findFocusElement(ViewGroup viewGroup) { + int numChildren = viewGroup.getChildCount(); + for (int i = 0; i < numChildren; i++) { + View child = viewGroup.getChildAt(i); + String sharedElementName = child.getSharedElementName(); + if (sharedElementName != null && !sharedElementName.startsWith("android:")) { + return child; + } + if (child instanceof ViewGroup) { + View sharedElement = findFocusElement((ViewGroup) child); + if (sharedElement != null) { + return sharedElement; + } + } + } + return null; + } + + private long calculateFallStartDelay(ViewGroup sceneRoot, View shared, 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); + if (shared != null) { + shared.getLocationOnScreen(loc); + float heroX = loc[0] + shared.getTranslationX() + (shared.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(); + distance += (1 - distanceXRatio) * shared.getHeight(); } float distanceRatio = distance/sceneRoot.getHeight() / 3; return Math.max(0, Math.round(distanceRatio * getDuration())); } - private long calculateRiseStartDelay(View sceneRoot, View view, int[] viewLoc) { + private long calculateRiseStartDelay(View sceneRoot, View shared, 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); + if (shared != null) { + shared.getLocationOnScreen(loc); + float heroX = loc[0] + shared.getTranslationX() + (shared.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(); + distance += distanceXRatio * shared.getHeight(); } float distanceRatio = distance/sceneRoot.getHeight() / 3; return Math.max(0, Math.round(distanceRatio * getDuration())); } + + @Override + public Transition clone() { + Fall transition = (Fall) super.clone(); + transition.mFocusElement = null; + return transition; + } } diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/ScaleTransition.java b/samples/ApiDemos/src/com/example/android/apis/animation/ScaleTransition.java new file mode 100644 index 000000000..787cdb374 --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/animation/ScaleTransition.java @@ -0,0 +1,87 @@ +/* + * 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.AnimatorSet; +import android.animation.ObjectAnimator; +import android.transition.Transition; +import android.transition.TransitionValues; +import android.util.Property; +import android.view.View; +import android.view.ViewGroup; + +/** + * + */ +public class ScaleTransition extends Transition { + private static final String PROPNAME_SCALE_X = "android:scale:x"; + private static final String PROPNAME_SCALE_Y = "android:scale:y"; + private static final String[] sTransitionProperties = { + PROPNAME_SCALE_X, + PROPNAME_SCALE_Y, + }; + + @Override + public String[] getTransitionProperties() { + return sTransitionProperties; + } + + @Override + public void captureStartValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Override + public void captureEndValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + private void captureValues(TransitionValues transitionValues) { + transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX()); + transitionValues.values.put(PROPNAME_SCALE_Y, transitionValues.view.getScaleY()); + } + + @Override + public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, + TransitionValues endValues) { + if (startValues == null || endValues == null) { + return null; + } + Animator scaleXAnimator = createScaleAnimator(startValues, endValues, PROPNAME_SCALE_X, + View.SCALE_X); + Animator scaleYAnimator = createScaleAnimator(startValues, endValues, PROPNAME_SCALE_Y, + View.SCALE_Y); + if (scaleXAnimator == null) { + return scaleYAnimator; + } else if (scaleYAnimator == null) { + return scaleXAnimator; + } + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether(scaleXAnimator, scaleYAnimator); + return animatorSet; + } + + private Animator createScaleAnimator(TransitionValues startValues, TransitionValues endValues, + String propertyName, Property scaleProperty) { + float start = (Float)startValues.values.get(propertyName); + float end = (Float)endValues.values.get(propertyName); + if (start == end) { + return null; + } + return ObjectAnimator.ofFloat(endValues.view, scaleProperty, start, end); + } +}