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

@@ -31,6 +31,7 @@ import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.data.ListUrlBuilder;
@@ -38,6 +39,7 @@ import com.hippo.ehviewer.ui.ContentActivity;
import com.hippo.ehviewer.widget.ContentLayout;
import com.hippo.ehviewer.widget.SearchLayout;
import com.hippo.scene.Scene;
import com.hippo.scene.TransitionCurtain;
import com.hippo.widget.Appbar;
public class GalleryListScene extends Scene implements SearchLayout.SearhLayoutHelper,
@@ -81,6 +83,16 @@ public class GalleryListScene extends Scene implements SearchLayout.SearhLayoutH
// TODO
mListView = inflater.inflate(R.layout.fragment_list, null);
Button bb = (Button) mListView.findViewById(R.id.test_button);
bb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startScene(TestScene.class, null, new TransitionCurtain(new TransitionCurtain.ViewPair[] {
new TransitionCurtain.ViewPair(R.id.haha, R.id.haha)
}));
}
});
// Main View
View sceneView = inflater.inflate(R.layout.scene_gallery_list, null);
mAppbar = (Appbar) sceneView.findViewById(R.id.appbar);
@@ -0,0 +1,44 @@
/*
* 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.ehviewer.ui.scene;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.ContentActivity;
import com.hippo.scene.Scene;
public class TestScene extends Scene {
private ContentActivity mActivity;
private Resources mResources;
@Override
public void onCreate(Bundle savedInstanceState) {
mActivity = (ContentActivity) getStageActivity();
mResources = mActivity.getResources();
}
@SuppressWarnings("InflateParams")
public View onCreateSceneView(Bundle savedInstanceState) {
LayoutInflater inflater = mActivity.getLayoutInflater();
return inflater.inflate(R.layout.scene_test, null);
}
}
@@ -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);
}
}
@@ -22,6 +22,7 @@ import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
public final class ViewUtils {
@@ -44,6 +45,17 @@ public final class ViewUtils {
* @param location an array of two integers in which to hold the coordinates
*/
public static void getLocationInWindow(View view, int[] location) {
getLocationInAncestor(view, location, android.R.id.content);
}
/**
* Get view location in ths ancestor
*
* @param view
* @param location
* @param ancestorId
*/
public static void getLocationInAncestor(View view, int[] location, int ancestorId) {
if (location == null || location.length < 2) {
throw new IllegalArgumentException(
"location must be an array of two integers");
@@ -57,7 +69,45 @@ public final class ViewUtils {
ViewParent viewParent = view.getParent();
while (viewParent instanceof View) {
view = (View) viewParent;
if (view.getId() == android.R.id.content) {
if (view.getId() == ancestorId) {
break;
}
position[0] -= view.getScrollX();
position[1] -= view.getScrollY();
position[0] += view.getLeft();
position[1] += view.getTop();
viewParent = view.getParent();
}
location[0] = (int) (position[0] + 0.5f);
location[1] = (int) (position[1] + 0.5f);
}
/**
* Get view location in ths ancestor
*
* @param view
* @param location
* @param ancestor
*/
public static void getLocationInAncestor(View view, int[] location, View ancestor) {
if (location == null || location.length < 2) {
throw new IllegalArgumentException(
"location must be an array of two integers");
}
float[] position = new float[2];
position[0] = view.getLeft();
position[1] = view.getTop();
ViewParent viewParent = view.getParent();
while (viewParent instanceof View) {
view = (View) viewParent;
if (viewParent == ancestor) {
break;
}
@@ -281,4 +331,18 @@ public final class ViewUtils {
return result;
}
/**
* removeOnGlobalLayoutListener
*
* @param vto
* @param l
*/
public static void removeOnGlobalLayoutListener(ViewTreeObserver vto,
ViewTreeObserver.OnGlobalLayoutListener l) {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
vto.removeGlobalOnLayoutListener(l);
} else {
vto.removeOnGlobalLayoutListener(l);
}
}
}
+7 -14
View File
@@ -19,24 +19,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
style="@style/ProgressBar.Small"
<ImageView
android:id="@+id/haha"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:layout_gravity="left|top"/>
android:src="@drawable/ic_happy"/>
<ProgressBar
style="@style/ProgressBar"
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar2"
android:layout_gravity="left|center_vertical"/>
android:text="Click"
android:id="@+id/test_button"
android:layout_gravity="center_horizontal|bottom"/>
<ProgressBar
style="@style/ProgressBar.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar3"
android:layout_gravity="left|bottom"/>
</FrameLayout>
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/haha"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="bottom|right"
android:src="@drawable/ic_happy"
android:scaleType="fitXY"/>
</FrameLayout>