Support changes in Scene Activity Transition API redo.

This reverts commit 1b3da3748f.

Change-Id: I84fd15c154a404ed10971025b7bb33f58a344965
This commit is contained in:
George Mount
2014-02-26 19:01:24 +00:00
parent 1b3da3748f
commit 4769ecc773
7 changed files with 293 additions and 330 deletions

View File

@@ -1295,8 +1295,8 @@
<activity android:name=".animation.ActivityTransition" <activity android:name=".animation.ActivityTransition"
android:label="Animation/Activity Transition" android:label="Animation/Activity Transition"
android:enabled="@bool/atLeastHoneycomb" android:enabled="@bool/atLeastHoneycomb"
android:theme="@style/ActivityTransitionTheme"> android:theme="@style/ActivityTransitionTheme">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" /> <category android:name="android.intent.category.SAMPLE_CODE" />
@@ -1304,9 +1304,9 @@
</activity> </activity>
<activity android:name=".animation.ActivityTransitionDetails" <activity android:name=".animation.ActivityTransitionDetails"
android:label="Animation/Activity Transition Details" android:label="Animation/Details of a specific thingy"
android:enabled="@bool/atLeastHoneycomb" android:enabled="@bool/atLeastHoneycomb"
android:theme="@style/ActivityTransitionTheme"> android:theme="@style/ActivityTransitionTheme">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
</intent-filter> </intent-filter>

View File

@@ -1,20 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipChildren="false" android:clipChildren="true"
android:columnCount="2" android:columnCount="2"
android:rowCount="4" android:rowCount="4"
> >
<ImageView android:id="@+id/ducky" <ImageView android:id="@+id/ducky"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:scaleType="center" android:scaleType="center"
android:src="@drawable/ducky"
android:layout_column="0" android:layout_column="0"
android:layout_row="0" android:layout_row="0"
android:src="@drawable/ducky"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="ducky"
/> />
<ImageView android:id="@+id/woot" <ImageView android:id="@+id/woot"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -24,6 +25,7 @@
android:layout_column="1" android:layout_column="1"
android:layout_row="0" android:layout_row="0"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="woot"
/> />
<ImageView android:id="@+id/ball" <ImageView android:id="@+id/ball"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -33,6 +35,7 @@
android:layout_column="0" android:layout_column="0"
android:layout_row="1" android:layout_row="1"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="ball"
/> />
<ImageView android:id="@+id/block" <ImageView android:id="@+id/block"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -42,6 +45,7 @@
android:layout_column="1" android:layout_column="1"
android:layout_row="1" android:layout_row="1"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="block"
/> />
<ImageView android:id="@+id/jellies" <ImageView android:id="@+id/jellies"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -51,6 +55,7 @@
android:layout_column="0" android:layout_column="0"
android:layout_row="2" android:layout_row="2"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="jellies"
/> />
<ImageView android:id="@+id/mug" <ImageView android:id="@+id/mug"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -60,6 +65,7 @@
android:layout_column="1" android:layout_column="1"
android:layout_row="2" android:layout_row="2"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="mug"
/> />
<ImageView android:id="@+id/pencil" <ImageView android:id="@+id/pencil"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -69,6 +75,7 @@
android:layout_column="0" android:layout_column="0"
android:layout_row="3" android:layout_row="3"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="pencil"
/> />
<ImageView android:id="@+id/scissors" <ImageView android:id="@+id/scissors"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -78,5 +85,6 @@
android:layout_column="1" android:layout_column="1"
android:layout_row="3" android:layout_row="3"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="scissors"
/> />
</GridLayout> </GridLayout>

View File

@@ -4,15 +4,22 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:clipChildren="false"
> >
<ImageView android:id="@+id/titleImage" <FrameLayout android:id="@+id/shared_element"
android:layout_height="0px" android:layout_height="0px"
android:layout_weight="1" android:layout_weight="1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:scaleType="centerCrop" android:sharedElementName="hero"
android:onClick="clicked" android:onClick="clicked"
android:sharedElementName="hero" android:clipChildren="false">
/> <ImageView android:id="@+id/titleImage"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:scaleType="center"
android:layout_gravity="left|bottom"
/>
</FrameLayout>
<LinearLayout android:layout_height="0px" <LinearLayout android:layout_height="0px"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_weight="2" android:layout_weight="2"
@@ -22,7 +29,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Ducky" android:text="Ducky"
android:textSize="30sp" android:textSize="30sp"
/> />
@@ -30,7 +37,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Woot!" android:text="Woot!"
android:textSize="30sp" android:textSize="30sp"
/> />
@@ -38,7 +45,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Ball" android:text="Ball"
android:textSize="30sp" android:textSize="30sp"
/> />
@@ -46,7 +53,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Block" android:text="Block"
android:textSize="30sp" android:textSize="30sp"
/> />
@@ -54,7 +61,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Jelly Bean" android:text="Jelly Bean"
android:textSize="30sp" android:textSize="30sp"
/> />
@@ -62,7 +69,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Mug" android:text="Mug"
android:textSize="30sp" android:textSize="30sp"
/> />
@@ -70,7 +77,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Pencil" android:text="Pencil"
android:textSize="30sp" android:textSize="30sp"
/> />
@@ -78,7 +85,7 @@
android:layout_height="2dp" android:layout_height="2dp"
android:background="#808080"/> android:background="#808080"/>
<TextView android:layout_height="wrap_content" <TextView android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:text="Scissors" android:text="Scissors"
android:textSize="30sp" android:textSize="30sp"
/> />

View File

@@ -17,23 +17,18 @@ package com.example.android.apis.animation;
import com.example.android.apis.R; 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.Activity;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.content.Intent; import android.content.Intent;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.transition.ChangeBounds;
import android.transition.Transition;
import android.transition.TransitionManager; import android.transition.TransitionManager;
import android.transition.TransitionSet; import android.transition.TransitionSet;
import android.util.Property; import android.util.ArrayMap;
import android.util.Pair;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.Window; import android.view.Window;
import android.widget.ImageView; import android.widget.ImageView;
@@ -43,138 +38,52 @@ import java.util.Random;
* *
*/ */
public class ActivityTransition extends Activity { public class ActivityTransition extends Activity {
private static final String TAG = "ActivityTransition"; 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 static final String KEY_ID = "ViewTransitionValues:id";
private Random mRandom = new Random(); private Random mRandom = new Random();
private boolean mComeBack;
private Fall mFall; private ImageView mHero;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS); requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setEarlyBackgroundTransition(false); getWindow().setTriggerEarlyEnterTransition(true);
getWindow().setBackgroundDrawable(new ColorDrawable(randomColor())); getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
setContentView(R.layout.image_block); setContentView(R.layout.image_block);
View hero = getHero(); setupHero();
if (hero != null) {
hero.setSharedElementName("hero");
}
TransitionManager transitionManager = getContentTransitionManager(); TransitionManager transitionManager = getContentTransitionManager();
TransitionSet transitions = new TransitionSet(); TransitionSet transitions = new TransitionSet();
Fall fall = new Fall(); Fall fall = new Fall();
fall.setDuration(600); fall.setDuration(600);
fall.setStartDelay(600);
fall.setHero(hero);
transitions.addTransition(fall); transitions.addTransition(fall);
transitions.addTransition(new ScaleTransition());
transitions.addTransition(new ChangeBounds());
transitions.addTransition(new Up()); transitions.addTransition(new Up());
transitionManager.setTransition("null", getContentScene(), transitions); transitionManager.setTransition(getContentScene(), transitions);
transitionManager.setExitTransition(getContentScene(), transitions);
transitions = new TransitionSet();
mFall = new Fall();
mFall.setDuration(600);
transitions.addTransition(mFall);
transitions.addTransition(new Up());
transitionManager.setTransition(getContentScene(), "null", transitions);
} }
@Override private void setupHero() {
protected void onResume() { int id = getIntent().getIntExtra(KEY_ID, 0);
super.onResume(); mHero = (ImageView) findViewById(id);
if (mComeBack) { if (mHero != null) {
mComeBack = false; ArrayMap<String, String> sharedElementsMap = new ArrayMap<String, String>();
setContentView(R.layout.image_block); 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, 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) { public void clicked(View v) {
v.setSharedElementName("hero"); mHero = (ImageView) v;
mFall.setHero(v);
Intent intent = new Intent(this, ActivityTransitionDetails.class); Intent intent = new Intent(this, ActivityTransitionDetails.class);
Bundle args = getHeroInfo(v); intent.putExtra(KEY_ID, v.getId());
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(args); ActivityOptions activityOptions
startActivity(intent, options.toBundle()); = ActivityOptions.makeSceneTransitionAnimation(mHero, "hero");
//v.setTranslationZ(300); startActivity(intent, activityOptions.toBundle());
mComeBack = true;
} }
private int randomColor() { private int randomColor() {
@@ -184,15 +93,25 @@ public class ActivityTransition extends Activity {
return 0xFF000000 | (red << 16) | (green << 8) | blue; return 0xFF000000 | (red << 16) | (green << 8) | blue;
} }
static Bundle getHeroInfo(View view) { @Override
int[] loc = new int[2]; public void onCaptureSharedElementStart(Transition transition) {
view.getLocationOnScreen(loc); int width = mHero.getWidth();
Bundle bundle = new Bundle(); int newTop = mHero.getBottom() - width;
bundle.putInt(KEY_LEFT_ON_SCREEN, loc[0]); mHero.setTop(newTop);
bundle.putInt(KEY_TOP_ON_SCREEN, loc[1]);
bundle.putInt(KEY_WIDTH, view.getWidth()); int imageWidth = mHero.getDrawable().getIntrinsicWidth();
bundle.putInt(KEY_HEIGHT, view.getHeight()); mHero.setPivotX(0);
bundle.putInt(KEY_ID, view.getId()); mHero.setPivotY(0);
return bundle; 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);
} }
} }

View File

@@ -17,26 +17,18 @@ package com.example.android.apis.animation;
import com.example.android.apis.R; 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.Activity;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.content.Intent; import android.content.Intent;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.transition.ChangeBounds;
import android.transition.Transition;
import android.transition.TransitionManager; import android.transition.TransitionManager;
import android.transition.TransitionSet; import android.transition.TransitionSet;
import android.util.Log; import android.util.Pair;
import android.util.Property;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
import android.view.Window; import android.view.Window;
import android.widget.ImageView; import android.widget.ImageView;
@@ -46,72 +38,94 @@ import java.util.Random;
* *
*/ */
public class ActivityTransitionDetails extends Activity { public class ActivityTransitionDetails extends Activity {
private static final String TAG = "ActivityTransitionDetails"; 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 static final String KEY_ID = "ViewTransitionValues:id";
private Random mRandom = new Random(); private Random mRandom = new Random();
private boolean mComeBack;
private int mImageResourceId = R.drawable.ducky; private int mImageResourceId = R.drawable.ducky;
private int mId;
private int mId = R.id.ducky;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS); requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setEarlyBackgroundTransition(false); getWindow().setTriggerEarlyEnterTransition(false);
getWindow().setBackgroundDrawable(new ColorDrawable(randomColor())); getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
setContentView(R.layout.image_details); setContentView(R.layout.image_details);
setImageMatrix(); ImageView titleImage = (ImageView) findViewById(R.id.titleImage);
ImageView hero = (ImageView)findViewById(R.id.titleImage); titleImage.setImageDrawable(getHeroDrawable());
hero.setImageDrawable(getHeroDrawable());
//hero.setTranslationZ(300);
TransitionManager transitionManager = getContentTransitionManager(); TransitionManager transitionManager = getContentTransitionManager();
TransitionSet transitions = new TransitionSet(); TransitionSet transitions = new TransitionSet();
Fall fall = new Fall(); Fall fall = new Fall();
fall.setDuration(600); fall.setDuration(600);
fall.setStartDelay(600);
transitions.addTransition(fall); transitions.addTransition(fall);
transitions.addTransition(new Up()); transitions.addTransition(new Up());
transitionManager.setTransition("null", getContentScene(), transitions); transitions.addTransition(new ChangeBounds());
transitions.addTransition(new ScaleTransition());
transitions = new TransitionSet(); transitionManager.setTransition(getContentScene(), transitions);
fall = new Fall(); transitionManager.setExitTransition(getContentScene(), transitions);
fall.setDuration(600);
transitions.addTransition(fall);
transitions.addTransition(new Up());
transitionManager.setTransition(getContentScene(), "null", transitions);
} }
@Override @Override
protected void onResume() { public void onCaptureSharedElementStart(Transition transition) {
super.onResume(); ImageView imageView = (ImageView) findViewById(R.id.titleImage);
if (mComeBack) { imageView.setScaleX(1);
mComeBack = false; imageView.setScaleY(1);
setContentView(R.layout.image_details); imageView.offsetTopAndBottom(-imageView.getTop());
ImageView hero = (ImageView)findViewById(R.id.titleImage); }
hero.setImageDrawable(getHeroDrawable());
setImageMatrix(); @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() { private Drawable getHeroDrawable() {
Bundle args = getTransitionArgs(); int id = getIntent().getIntExtra(KEY_ID, mId);
int id = args == null ? 0 : args.getInt(KEY_ID); mId = id;
int resourceId; int resourceId;
switch (id) { switch (id) {
case R.id.ducky: resourceId = R.drawable.ducky; break; case R.id.ducky:
case R.id.jellies: resourceId = R.drawable.jellies; break; resourceId = R.drawable.ducky;
case R.id.mug: resourceId = R.drawable.mug; break; break;
case R.id.pencil: resourceId = R.drawable.pencil; break; case R.id.jellies:
case R.id.scissors: resourceId = R.drawable.scissors; break; resourceId = R.drawable.jellies;
case R.id.woot: resourceId = R.drawable.woot; break; break;
case R.id.ball: resourceId = R.drawable.ball; break; case R.id.mug:
case R.id.block: resourceId = R.drawable.block; break; 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: default:
resourceId = mImageResourceId; resourceId = mImageResourceId;
break; break;
@@ -120,96 +134,11 @@ public class ActivityTransitionDetails extends Activity {
return getResources().getDrawable(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) { public void clicked(View v) {
Intent intent = new Intent(this, ActivityTransition.class); Intent intent = new Intent(this, ActivityTransition.class);
Bundle args = getHeroInfo((ImageView)v); intent.putExtra(KEY_ID, mId);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(args); ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(v, "hero");
startActivity(intent, options.toBundle()); startActivity(intent, activityOptions.toBundle());
mComeBack = true;
} }
private int randomColor() { private int randomColor() {
@@ -219,22 +148,4 @@ public class ActivityTransitionDetails extends Activity {
return 0xFF000000 | (red << 16) | (green << 8) | blue; 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

@@ -20,11 +20,9 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator; import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.transition.Transition; import android.transition.Transition;
import android.transition.TransitionValues; import android.transition.TransitionValues;
import android.transition.Visibility; import android.transition.Visibility;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator; import android.view.animation.AccelerateInterpolator;
@@ -39,11 +37,7 @@ public class Fall extends Visibility {
private static final String TAG = "Fall"; private static final String TAG = "Fall";
private static final String PROPNAME_SCREEN_LOCATION = "android:fade:screen_location"; private static final String PROPNAME_SCREEN_LOCATION = "android:fade:screen_location";
private View mHero; private View mFocusElement;
public void setHero(View hero) {
mHero = hero;
}
private Animator createAnimation(final View view, long startDelay, final float startY, private Animator createAnimation(final View view, long startDelay, final float startY,
float endY, AnimatorListenerAdapter listener, TimeInterpolator interpolator) { float endY, AnimatorListenerAdapter listener, TimeInterpolator interpolator) {
@@ -99,7 +93,6 @@ public class Fall extends Visibility {
return null; return null;
} }
final View endView = endValues.view; final View endView = endValues.view;
Log.v(TAG, "onAppear: " + endView.getId());
final float endY = endView.getTranslationY(); final float endY = endView.getTranslationY();
final float startY = endY + sceneRoot.getHeight(); final float startY = endY + sceneRoot.getHeight();
@@ -136,8 +129,9 @@ public class Fall extends Visibility {
} }
}; };
addListener(transitionListener); addListener(transitionListener);
View sharedElement = getFocusElement(sceneRoot);
int[] loc = (int[]) endValues.values.get(PROPNAME_SCREEN_LOCATION); 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); return createAnimation(endView, startDelay, startY, endY, null, sDecelerate);
} }
@@ -190,12 +184,13 @@ public class Fall extends Visibility {
} }
} }
final int finalVisibility = endVisibility; final int finalVisibility = endVisibility;
View sharedElement = getFocusElement(sceneRoot);
int[] loc = (int[]) startValues.values.get(PROPNAME_SCREEN_LOCATION); int[] loc = (int[]) startValues.values.get(PROPNAME_SCREEN_LOCATION);
// TODO: add automatic facility to Visibility superclass for keeping views around // TODO: add automatic facility to Visibility superclass for keeping views around
if (overlayView != null) { if (overlayView != null) {
// TODO: Need to do this for general case of adding to overlay // 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 screenX = loc[0];
int screenY = loc[1]; int screenY = loc[1];
loc = new int[2]; loc = new int[2];
@@ -240,7 +235,7 @@ public class Fall extends Visibility {
return createAnimation(view, startDelay, startY, endY, endListener, sAccelerate); return createAnimation(view, startDelay, startY, endY, endListener, sAccelerate);
} }
if (viewToKeep != null) { 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 // TODO: find a different way to do this, like just changing the view to be
// VISIBLE for the duration of the transition // VISIBLE for the duration of the transition
viewToKeep.setVisibility((View.VISIBLE)); viewToKeep.setVisibility((View.VISIBLE));
@@ -299,37 +294,73 @@ public class Fall extends Visibility {
return null; 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]; int[] loc = new int[2];
sceneRoot.getLocationOnScreen(loc); sceneRoot.getLocationOnScreen(loc);
int bottom = loc[1] + sceneRoot.getHeight(); int bottom = loc[1] + sceneRoot.getHeight();
float distance = bottom - viewLoc[1] + view.getTranslationY(); float distance = bottom - viewLoc[1] + view.getTranslationY();
if (mHero != null) { if (shared != null) {
mHero.getLocationOnScreen(loc); shared.getLocationOnScreen(loc);
float heroX = loc[0] + mHero.getTranslationX() + (mHero.getWidth() / 2.0f); float heroX = loc[0] + shared.getTranslationX() + (shared.getWidth() / 2.0f);
float viewX = viewLoc[0] + view.getTranslationX() + (view.getWidth() / 2.0f); float viewX = viewLoc[0] + view.getTranslationX() + (view.getWidth() / 2.0f);
float distanceX = Math.abs(heroX - viewX); float distanceX = Math.abs(heroX - viewX);
float distanceXRatio = distanceX / sceneRoot.getWidth(); float distanceXRatio = distanceX / sceneRoot.getWidth();
distance += (1 - distanceXRatio) * mHero.getHeight(); distance += (1 - distanceXRatio) * shared.getHeight();
} }
float distanceRatio = distance/sceneRoot.getHeight() / 3; float distanceRatio = distance/sceneRoot.getHeight() / 3;
return Math.max(0, Math.round(distanceRatio * getDuration())); 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]; int[] loc = new int[2];
sceneRoot.getLocationOnScreen(loc); sceneRoot.getLocationOnScreen(loc);
int top = loc[1]; int top = loc[1];
float distance = viewLoc[1] + view.getTranslationY() - top; float distance = viewLoc[1] + view.getTranslationY() - top;
if (mHero != null) { if (shared != null) {
mHero.getLocationOnScreen(loc); shared.getLocationOnScreen(loc);
float heroX = loc[0] + mHero.getTranslationX() + (mHero.getWidth() / 2.0f); float heroX = loc[0] + shared.getTranslationX() + (shared.getWidth() / 2.0f);
float viewX = viewLoc[0] + view.getTranslationX() + (view.getWidth() / 2.0f); float viewX = viewLoc[0] + view.getTranslationX() + (view.getWidth() / 2.0f);
float distanceX = Math.abs(heroX - viewX); float distanceX = Math.abs(heroX - viewX);
float distanceXRatio = distanceX / sceneRoot.getWidth(); float distanceXRatio = distanceX / sceneRoot.getWidth();
distance += distanceXRatio * mHero.getHeight(); distance += distanceXRatio * shared.getHeight();
} }
float distanceRatio = distance/sceneRoot.getHeight() / 3; float distanceRatio = distance/sceneRoot.getHeight() / 3;
return Math.max(0, Math.round(distanceRatio * getDuration())); return Math.max(0, Math.round(distanceRatio * getDuration()));
} }
@Override
public Transition clone() {
Fall transition = (Fall) super.clone();
transition.mFocusElement = null;
return transition;
}
} }

View File

@@ -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<View, Float> 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);
}
}