Update Scene
This commit is contained in:
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 :
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user