Use framework Transition MoveImage and Slide

Change-Id: I3c55ee699288f1945ae0a23dfad2ae4fd9caa9a0
This commit is contained in:
George Mount
2014-02-26 13:05:43 -08:00
parent 2afda8f4bd
commit b3059f8744
9 changed files with 140 additions and 685 deletions

View File

@@ -10,7 +10,7 @@
<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="centerCrop"
android:layout_column="0" android:layout_column="0"
android:layout_row="0" android:layout_row="0"
android:src="@drawable/ducky" android:src="@drawable/ducky"
@@ -20,7 +20,7 @@
<ImageView android:id="@+id/woot" <ImageView android:id="@+id/woot"
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="centerCrop"
android:src="@drawable/woot" android:src="@drawable/woot"
android:layout_column="1" android:layout_column="1"
android:layout_row="0" android:layout_row="0"
@@ -30,7 +30,7 @@
<ImageView android:id="@+id/ball" <ImageView android:id="@+id/ball"
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="centerCrop"
android:src="@drawable/ball" android:src="@drawable/ball"
android:layout_column="0" android:layout_column="0"
android:layout_row="1" android:layout_row="1"
@@ -40,7 +40,7 @@
<ImageView android:id="@+id/block" <ImageView android:id="@+id/block"
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="centerCrop"
android:src="@drawable/block" android:src="@drawable/block"
android:layout_column="1" android:layout_column="1"
android:layout_row="1" android:layout_row="1"
@@ -50,7 +50,7 @@
<ImageView android:id="@+id/jellies" <ImageView android:id="@+id/jellies"
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="centerCrop"
android:src="@drawable/jellies" android:src="@drawable/jellies"
android:layout_column="0" android:layout_column="0"
android:layout_row="2" android:layout_row="2"
@@ -60,7 +60,7 @@
<ImageView android:id="@+id/mug" <ImageView android:id="@+id/mug"
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="centerCrop"
android:src="@drawable/mug" android:src="@drawable/mug"
android:layout_column="1" android:layout_column="1"
android:layout_row="2" android:layout_row="2"
@@ -70,7 +70,7 @@
<ImageView android:id="@+id/pencil" <ImageView android:id="@+id/pencil"
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="centerCrop"
android:src="@drawable/pencil" android:src="@drawable/pencil"
android:layout_column="0" android:layout_column="0"
android:layout_row="3" android:layout_row="3"
@@ -80,7 +80,7 @@
<ImageView android:id="@+id/scissors" <ImageView android:id="@+id/scissors"
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="centerCrop"
android:src="@drawable/scissors" android:src="@drawable/scissors"
android:layout_column="1" android:layout_column="1"
android:layout_row="3" android:layout_row="3"

View File

@@ -4,22 +4,15 @@
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"
> >
<FrameLayout android:id="@+id/shared_element" <ImageView android:id="@+id/titleImage"
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:sharedElementName="hero" android:scaleType="centerCrop"
android:onClick="clicked" android:sharedElementName="hero"
android:clipChildren="false"> android:onClick="clicked"
<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"
@@ -32,6 +25,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Ducky" android:text="Ducky"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
<View android:layout_width="match_parent" <View android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
@@ -40,6 +34,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Woot!" android:text="Woot!"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
<View android:layout_width="match_parent" <View android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
@@ -48,6 +43,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Ball" android:text="Ball"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
<View android:layout_width="match_parent" <View android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
@@ -56,6 +52,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Block" android:text="Block"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
<View android:layout_width="match_parent" <View android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
@@ -64,6 +61,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Jelly Bean" android:text="Jelly Bean"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
<View android:layout_width="match_parent" <View android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
@@ -72,6 +70,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Mug" android:text="Mug"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
<View android:layout_width="match_parent" <View android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
@@ -80,6 +79,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Pencil" android:text="Pencil"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
<View android:layout_width="match_parent" <View android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
@@ -88,6 +88,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="Scissors" android:text="Scissors"
android:textSize="30sp" android:textSize="30sp"
android:textColor="#FFF"
/> />
</LinearLayout> </LinearLayout>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- BEGIN_INCLUDE(Explode) -->
<explode/>
<!-- END_INCLUDE(Explode) -->

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- BEGIN_INCLUDE(MoveImage) -->
<moveImage/>
<!-- END_INCLUDE(MoveImage) -->

View File

@@ -22,12 +22,11 @@ import android.app.ActivityOptions;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.transition.ChangeBounds; import android.transition.MoveImage;
import android.transition.Transition; import android.transition.Slide;
import android.transition.TransitionManager; import android.transition.TransitionManager;
import android.transition.TransitionSet; import android.transition.TransitionSet;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Pair;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.Window;
import android.widget.ImageView; import android.widget.ImageView;
@@ -47,30 +46,81 @@ public class ActivityTransition extends Activity {
private ImageView mHero; private ImageView mHero;
public static final int[] DRAWABLES = {
R.drawable.ball,
R.drawable.block,
R.drawable.ducky,
R.drawable.jellies,
R.drawable.mug,
R.drawable.pencil,
R.drawable.scissors,
R.drawable.woot,
};
public static final int[] IDS = {
R.id.ball,
R.id.block,
R.id.ducky,
R.id.jellies,
R.id.mug,
R.id.pencil,
R.id.scissors,
R.id.woot,
};
public static final String[] NAMES = {
"ball",
"block",
"ducky",
"jellies",
"mug",
"pencil",
"scissors",
"woot",
};
public static int getIdForKey(String id) {
return IDS[getIndexForKey(id)];
}
public static int getDrawableIdForKey(String id) {
return DRAWABLES[getIndexForKey(id)];
}
public static int getIndexForKey(String id) {
for (int i = 0; i < NAMES.length; i++) {
String name = NAMES[i];
if (name.equals(id)) {
return i;
}
}
return 2;
}
@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);
getWindow().setTriggerEarlyEnterTransition(true); getWindow().setAllowOverlappingEnterTransition(true);
getWindow().setAllowOverlappingExitTransition(true);
getWindow().setBackgroundDrawable(new ColorDrawable(randomColor())); getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
setContentView(R.layout.image_block); setContentView(R.layout.image_block);
setupHero(); setupHero();
TransitionManager transitionManager = getContentTransitionManager(); TransitionManager transitionManager = getContentTransitionManager();
TransitionSet transitions = new TransitionSet(); TransitionSet transitions = new TransitionSet();
Fall fall = new Fall(); Slide slide = new Slide();
fall.setDuration(600); slide.setDuration(600);
transitions.addTransition(fall); transitions.addTransition(slide);
transitions.addTransition(new ScaleTransition()); transitions.addTransition(new MoveImage());
transitions.addTransition(new ChangeBounds());
transitions.addTransition(new Up());
transitionManager.setTransition(getContentScene(), transitions); transitionManager.setTransition(getContentScene(), transitions);
transitionManager.setExitTransition(getContentScene(), transitions); transitionManager.setExitTransition(getContentScene(), transitions);
} }
private void setupHero() { private void setupHero() {
int id = getIntent().getIntExtra(KEY_ID, 0); String name = getIntent().getStringExtra(KEY_ID);
mHero = (ImageView) findViewById(id); mHero = null;
if (mHero != null) { if (name != null) {
mHero = (ImageView) findViewById(getIdForKey(name));
ArrayMap<String, String> sharedElementsMap = new ArrayMap<String, String>(); ArrayMap<String, String> sharedElementsMap = new ArrayMap<String, String>();
sharedElementsMap.put("hero", mHero.getSharedElementName()); sharedElementsMap.put("hero", mHero.getSharedElementName());
getWindow().mapTransitionTargets(sharedElementsMap); getWindow().mapTransitionTargets(sharedElementsMap);
@@ -80,7 +130,7 @@ public class ActivityTransition extends Activity {
public void clicked(View v) { public void clicked(View v) {
mHero = (ImageView) v; mHero = (ImageView) v;
Intent intent = new Intent(this, ActivityTransitionDetails.class); Intent intent = new Intent(this, ActivityTransitionDetails.class);
intent.putExtra(KEY_ID, v.getId()); intent.putExtra(KEY_ID, v.getSharedElementName());
ActivityOptions activityOptions ActivityOptions activityOptions
= ActivityOptions.makeSceneTransitionAnimation(mHero, "hero"); = ActivityOptions.makeSceneTransitionAnimation(mHero, "hero");
startActivity(intent, activityOptions.toBundle()); startActivity(intent, activityOptions.toBundle());
@@ -92,26 +142,4 @@ public class ActivityTransition extends Activity {
int blue = mRandom.nextInt(128); int blue = mRandom.nextInt(128);
return 0xFF000000 | (red << 16) | (green << 8) | blue; return 0xFF000000 | (red << 16) | (green << 8) | blue;
} }
@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);
}
} }

View File

@@ -23,11 +23,10 @@ import android.content.Intent;
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.MoveImage;
import android.transition.Transition; import android.transition.Slide;
import android.transition.TransitionManager; import android.transition.TransitionManager;
import android.transition.TransitionSet; import android.transition.TransitionSet;
import android.util.Pair;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.Window;
import android.widget.ImageView; import android.widget.ImageView;
@@ -47,13 +46,14 @@ public class ActivityTransitionDetails extends Activity {
private int mImageResourceId = R.drawable.ducky; private int mImageResourceId = R.drawable.ducky;
private int mId = R.id.ducky; private String mName = "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);
getWindow().setTriggerEarlyEnterTransition(false); getWindow().setAllowOverlappingEnterTransition(false);
getWindow().setAllowOverlappingExitTransition(true);
getWindow().setBackgroundDrawable(new ColorDrawable(randomColor())); getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
setContentView(R.layout.image_details); setContentView(R.layout.image_details);
ImageView titleImage = (ImageView) findViewById(R.id.titleImage); ImageView titleImage = (ImageView) findViewById(R.id.titleImage);
@@ -62,81 +62,27 @@ public class ActivityTransitionDetails extends Activity {
TransitionManager transitionManager = getContentTransitionManager(); TransitionManager transitionManager = getContentTransitionManager();
TransitionSet transitions = new TransitionSet(); TransitionSet transitions = new TransitionSet();
Fall fall = new Fall(); Slide slide = new Slide();
fall.setDuration(600); slide.setDuration(600);
transitions.addTransition(fall); transitions.addTransition(slide);
transitions.addTransition(new Up()); transitions.addTransition(new MoveImage());
transitions.addTransition(new ChangeBounds());
transitions.addTransition(new ScaleTransition());
transitionManager.setTransition(getContentScene(), transitions); transitionManager.setTransition(getContentScene(), transitions);
transitionManager.setExitTransition(getContentScene(), transitions); transitionManager.setExitTransition(getContentScene(), transitions);
} }
@Override
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() { private Drawable getHeroDrawable() {
int id = getIntent().getIntExtra(KEY_ID, mId); String name = getIntent().getStringExtra(KEY_ID);
mId = id; if (name != null) {
mName = name;
int resourceId; mImageResourceId = ActivityTransition.getDrawableIdForKey(name);
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); return getResources().getDrawable(mImageResourceId);
} }
public void clicked(View v) { public void clicked(View v) {
Intent intent = new Intent(this, ActivityTransition.class); Intent intent = new Intent(this, ActivityTransition.class);
intent.putExtra(KEY_ID, mId); intent.putExtra(KEY_ID, mName);
ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(v, "hero"); ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(v, "hero");
startActivity(intent, activityOptions.toBundle()); startActivity(intent, activityOptions.toBundle());
} }

View File

@@ -1,366 +0,0 @@
/*
* 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.transition.Transition;
import android.transition.TransitionValues;
import android.transition.Visibility;
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 mFocusElement;
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;
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);
View sharedElement = getFocusElement(sceneRoot);
int[] loc = (int[]) endValues.values.get(PROPNAME_SCREEN_LOCATION);
long startDelay = calculateRiseStartDelay(sceneRoot, sharedElement, 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;
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, sharedElement, 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, 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));
// 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 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 (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) * shared.getHeight();
}
float distanceRatio = distance/sceneRoot.getHeight() / 3;
return Math.max(0, Math.round(distanceRatio * getDuration()));
}
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 (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 * 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;
}
}

View File

@@ -1,87 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,103 +0,0 @@
/*
* 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);
}
}