Update Scene

This commit is contained in:
seven332 committed 2015-03-23 16:25:46 +08:00
1 parent 9c3c0e929a
commit a95e708144
11 files changed
+377 -37

No files matched your search

@@ -17,12 +17,13 @@ package com.hippo.scene;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import java.io.Serializable;
public class Announcer {
private Bundle mExtras;
private @Nullable Bundle mExtras;
public boolean getBooleanExtra(String name, boolean defaultValue) {
return mExtras == null ? defaultValue :
+16 -1
View File
@@ -15,5 +15,20 @@
package com.hippo.scene;
public class Curtain {
import android.support.annotation.NonNull;
public abstract class Curtain {
public abstract void open(@NonNull Scene enter, @NonNull Scene exit);
public abstract void close(@NonNull Scene enter, @NonNull Scene exit);
/**
* Call it after {@link #close}
*
* @param scene the scene
*/
protected void dispatchDetachFromeStage(Scene scene) {
scene.detachFromeStage();
}
}
+17 -6
View File
@@ -44,18 +44,27 @@ public abstract class Scene {
}
// If there is no StageActivity for SceneManager, yout will get AssertError
public StageActivity getStageActivity() {
public @NonNull StageActivity getStageActivity() {
StageActivity stageActivity = sSceneManager.getStageActivity();
AssertUtils.assertNotNull("StageActivity is null", stageActivity);
return stageActivity;
}
View getSceneView() {
@Nullable View getSceneView() {
return mSceneView;
}
public void startScene(@NonNull Class sceneClass) {
sSceneManager.startScene(sceneClass, null, null);
}
public void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer) {
sSceneManager.startScene(sceneClass, announcer);
sSceneManager.startScene(sceneClass, announcer, null);
}
public void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer,
@Nullable Curtain curtain) {
sSceneManager.startScene(sceneClass, announcer, curtain);
}
public final void finish() {
@@ -78,11 +87,13 @@ public abstract class Scene {
onPause();
}
void destroy() {
void destroy(boolean removeScene) {
onDestroy();
// Make sure scene view is detached from stage
detachFromeStage();
if (removeScene) {
// Make sure scene view is detached from stage
detachFromeStage();
}
}
/**
@@ -18,6 +18,7 @@ package com.hippo.scene;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import com.hippo.util.Log;
@@ -27,7 +28,7 @@ class SceneManager {
private static final String TAG = SceneManager.class.getSimpleName();
private Stack<Scene> mSceneStack = new Stack<>();
private Stack<Pair<Scene, Curtain>> mSceneStack = new Stack<>();
private StageActivity mStageActivity;
// Should only be called by SceneApplication
@@ -42,7 +43,8 @@ class SceneManager {
return mStageActivity;
}
void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer) {
void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer,
@Nullable Curtain curtain) {
Scene scene;
try {
scene = (Scene) sceneClass.newInstance();
@@ -55,25 +57,55 @@ class SceneManager {
throw new IllegalStateException(sceneClass.getName() + " can not cast to scene");
}
Scene topScene = getTopState();
if (topScene != null) {
topScene.pause();
Scene previousState = getTopState();
if (previousState != null) {
previousState.pause();
}
mSceneStack.push(scene);
mSceneStack.push(new Pair<>(scene, curtain));
scene.create(null);
scene.resume();
// Do animation via curtain
if (curtain != null && previousState != null) {
curtain.open(scene, previousState);
}
}
void finishScene(@NonNull Scene scene) {
if (mSceneStack.remove(scene)) {
scene.destroy();
int index = getSceneIndex(scene);
if (index >= 0 && index < mSceneStack.size()) {
Pair<Scene, Curtain> pair = mSceneStack.remove(index);
Curtain curtain = pair.second;
Scene previousState = getTopState();
// Do animation via curtain
if (curtain != null) {
scene.destroy(false);
if (previousState != null) {
curtain.open(previousState, scene);
}
} else {
scene.destroy(true);
}
} else {
Log.e(TAG, "The scene is not in stage");
}
}
private int getSceneIndex(@NonNull Scene scene) {
int size = mSceneStack.size();
while (--size >= 0) {
Pair<Scene, Curtain> pair = mSceneStack.get(size);
if (scene.equals(pair.first)) {
return size;
}
}
return -1;
}
boolean onBackPressed() {
Scene scene = getTopState();
if (scene != null) {
@@ -87,29 +119,32 @@ class SceneManager {
private Scene getTopState() {
if (!mSceneStack.isEmpty()) {
return mSceneStack.peek();
return mSceneStack.peek().first;
} else {
return null;
}
}
/*
private Scene getSecondTopState() {
int secondTopIndex = mSceneStack.size() - 2;
if (secondTopIndex >= 0) {
return mSceneStack.get(secondTopIndex);
return mSceneStack.get(secondTopIndex).first;
} else {
return null;
}
}
*/
protected void onSaveInstanceState(Bundle outState) {
for (Scene scene : mSceneStack) {
scene.saveInstanceState(outState);
for (Pair<Scene, Curtain> p : mSceneStack) {
p.first.saveInstanceState(outState);
}
}
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
for (Scene scene : mSceneStack) {
for (Pair<Scene, Curtain> p : mSceneStack) {
Scene scene = p.first;
// Recreate
scene.create(savedInstanceState);
scene.resume();
@@ -66,7 +66,7 @@ public abstract class StageActivity extends AbsActionBarActivity {
}
public void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer) {
sSceneManager.startScene(sceneClass, announcer);
sSceneManager.startScene(sceneClass, announcer, null);
}
/**
@@ -0,0 +1,135 @@
/*
* Copyright (C) 2015 Hippo Seven
*
* 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
* 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.hippo.scene;
import android.animation.ObjectAnimator;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewTreeObserver;
import com.hippo.util.ViewUtils;
public class TransitionCurtain extends Curtain {
private static long ANIMATE_TIME = 300L;
private ViewPair[] mViewPairArray;
public TransitionCurtain(ViewPair[] viewPairArray) {
mViewPairArray = viewPairArray;
}
@Override
public void open(final @NonNull Scene enter, final @NonNull Scene exit) {
for (ViewPair pair : mViewPairArray) {
final View enterView = pair.getToView(enter);
final View exitView = pair.getFromView(exit);
if (enterView == null || exitView == null) {
// Can't get to view
continue;
}
// First make enter view invisible
ViewUtils.setVisibility(enterView, View.INVISIBLE);
enterView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
ViewUtils.removeOnGlobalLayoutListener(enterView.getViewTreeObserver(), this);
int[] startloaction = new int[2];
ViewUtils.getLocationInAncestor(exitView, startloaction, exit.getStageActivity().getStageLayout());
int[] endloaction = new int[2];
ViewUtils.getLocationInAncestor(enterView, endloaction, enter.getStageActivity().getStageLayout());
int startWidth = exitView.getWidth();
int startHeight = exitView.getHeight();
int endWidth = enterView.getWidth();
int endHeight = enterView.getHeight();
ViewUtils.setVisibility(exitView, View.INVISIBLE);
ViewUtils.setVisibility(enterView, View.VISIBLE);
// Start animation
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(enterView, "scaleX", (float) startWidth / endWidth, 1f);
scaleXAnim.setDuration(ANIMATE_TIME);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(enterView, "scaleY", (float) startHeight / endHeight, 1f);
scaleYAnim.setDuration(ANIMATE_TIME);
ObjectAnimator xAnim = ObjectAnimator.ofFloat(enterView, "x", startloaction[0], endloaction[0]);
xAnim.setDuration(ANIMATE_TIME);
ObjectAnimator yAnim = ObjectAnimator.ofFloat(enterView, "y", startloaction[1], endloaction[1]);
yAnim.setDuration(ANIMATE_TIME);
scaleXAnim.start();
scaleYAnim.start();
xAnim.start();
yAnim.start();
}
});
}
}
@Override
public void close(@NonNull Scene enter, @NonNull Scene exit) {
dispatchDetachFromeStage(exit);
}
public static class ViewPair {
private int[] mIds;
private GetViewHelper mHelper;
public ViewPair(int from, int to) {
mIds = new int[]{from, to};
}
public ViewPair(@NonNull GetViewHelper helper) {
mHelper = helper;
}
private @Nullable View getFromView(Scene scene) {
View sceneView = scene.getSceneView();
if (mIds != null && sceneView != null) {
return sceneView.findViewById(mIds[0]);
}
if (mHelper != null) {
return mHelper.getFromView(sceneView);
}
return null;
}
private @Nullable View getToView(Scene scene) {
View sceneView = scene.getSceneView();
if (mIds != null && sceneView != null) {
return sceneView.findViewById(mIds[1]);
}
if (mHelper != null) {
return mHelper.getToView(sceneView);
}
return null;
}
}
public abstract static class GetViewHelper {
public abstract View getFromView(@Nullable View sceneView);
public abstract View getToView(@Nullable View sceneView);
}
}