Daniel Zlotin 6 years ago
parent
commit
5fc7df8743

+ 92
- 36
lib/android/app/src/main/java/com/reactnativenavigation/anim/StackAnimator.java View File

1
 package com.reactnativenavigation.anim;
1
 package com.reactnativenavigation.anim;
2
 
2
 
3
+import android.animation.Animator;
4
+import android.animation.AnimatorSet;
5
+import android.animation.ObjectAnimator;
6
+import android.app.Activity;
3
 import android.content.Context;
7
 import android.content.Context;
4
-import android.content.res.TypedArray;
5
 import android.support.annotation.Nullable;
8
 import android.support.annotation.Nullable;
9
+import android.util.DisplayMetrics;
6
 import android.view.View;
10
 import android.view.View;
7
-import android.view.animation.Animation;
8
-import android.view.animation.AnimationUtils;
11
+import android.view.WindowManager;
12
+import android.view.animation.AccelerateInterpolator;
13
+import android.view.animation.DecelerateInterpolator;
9
 
14
 
10
 @SuppressWarnings("ResourceType")
15
 @SuppressWarnings("ResourceType")
11
 public class StackAnimator {
16
 public class StackAnimator {
12
 
17
 
13
-	private static int androidOpenEnterAnimResId;
14
-	private static int androidOpenExitAnimResId;
15
-	private static int androidCloseEnterAnimResId;
16
-	private static int androidCloseExitAnimResId;
17
-	private final Context context;
18
+	public interface StackAnimationListener {
19
+		void onAnimationEnd();
20
+	}
21
+
22
+	private static final int DURATION = 300;
23
+	private static final int START_DELAY = 100;
24
+	private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
25
+	private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
26
+	private float translationY;
18
 
27
 
19
 	public StackAnimator(Context context) {
28
 	public StackAnimator(Context context) {
20
-		this.context = context;
21
-		loadResIfNeeded(context);
29
+		translationY = getWindowHeight(context);
22
 	}
30
 	}
23
 
31
 
24
-	private void loadResIfNeeded(Context context) {
25
-		if (androidOpenEnterAnimResId > 0) return;
32
+	public void animatePush(final View view, @Nullable final StackAnimationListener animationListener) {
33
+		view.setVisibility(View.INVISIBLE);
34
+		ObjectAnimator alpha = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1);
35
+		alpha.setInterpolator(DECELERATE_INTERPOLATOR);
26
 
36
 
27
-		int[] attrs = {android.R.attr.activityOpenEnterAnimation, android.R.attr.activityOpenExitAnimation, android.R.attr.activityCloseEnterAnimation, android.R.attr.activityCloseExitAnimation};
28
-		TypedArray typedArray = context.obtainStyledAttributes(android.R.style.Animation_Activity, attrs);
29
-		androidOpenEnterAnimResId = typedArray.getResourceId(0, -1);
30
-		androidOpenExitAnimResId = typedArray.getResourceId(1, -1);
31
-		androidCloseEnterAnimResId = typedArray.getResourceId(2, -1);
32
-		androidCloseExitAnimResId = typedArray.getResourceId(3, -1);
33
-		typedArray.recycle();
34
-	}
37
+		AnimatorSet set = new AnimatorSet();
38
+		set.addListener(new Animator.AnimatorListener() {
39
+			@Override
40
+			public void onAnimationStart(Animator animation) {
41
+				view.setVisibility(View.VISIBLE);
42
+			}
43
+
44
+			@Override
45
+			public void onAnimationEnd(Animator animation) {
46
+				if (animationListener != null) {
47
+					animationListener.onAnimationEnd();
48
+				}
49
+			}
35
 
50
 
36
-	public void animatePush(final View enteringView, final View exitingView, @Nullable final Runnable onComplete) {
37
-		Animation enterAnim = AnimationUtils.loadAnimation(context, androidOpenEnterAnimResId);
38
-		Animation exitAnim = AnimationUtils.loadAnimation(context, androidOpenExitAnimResId);
51
+			@Override
52
+			public void onAnimationCancel(Animator animation) {
39
 
53
 
40
-		new ViewAnimationSetBuilder()
41
-				.withEndListener(onComplete)
42
-				.add(enteringView, enterAnim)
43
-				.add(exitingView, exitAnim)
44
-				.start();
54
+			}
55
+
56
+			@Override
57
+			public void onAnimationRepeat(Animator animation) {
58
+
59
+			}
60
+		});
61
+		ObjectAnimator translationY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, this.translationY, 0);
62
+		translationY.setInterpolator(DECELERATE_INTERPOLATOR);
63
+		translationY.setDuration(DURATION);
64
+		alpha.setDuration(DURATION);
65
+		set.playTogether(translationY, alpha);
66
+		set.start();
45
 	}
67
 	}
46
 
68
 
47
-	public void animatePop(final View enteringView, final View exitingView, @Nullable final Runnable onComplete) {
48
-		Animation enterAnim = AnimationUtils.loadAnimation(context, androidCloseEnterAnimResId);
49
-		Animation exitAnim = AnimationUtils.loadAnimation(context, androidCloseExitAnimResId);
69
+	public void animatePop(View view, @Nullable final StackAnimationListener animationListener) {
70
+		ObjectAnimator alpha = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0);
71
+		alpha.setInterpolator(ACCELERATE_INTERPOLATOR);
72
+
73
+		AnimatorSet set = new AnimatorSet();
74
+		set.addListener(new Animator.AnimatorListener() {
75
+			@Override
76
+			public void onAnimationStart(Animator animation) {
77
+
78
+			}
50
 
79
 
51
-		new ViewAnimationSetBuilder()
52
-				.withEndListener(onComplete)
53
-				.add(enteringView, enterAnim)
54
-				.add(exitingView, exitAnim)
55
-				.start();
80
+			@Override
81
+			public void onAnimationEnd(Animator animation) {
82
+				if (animationListener != null) {
83
+					animationListener.onAnimationEnd();
84
+				}
85
+			}
86
+
87
+			@Override
88
+			public void onAnimationCancel(Animator animation) {
89
+
90
+			}
91
+
92
+			@Override
93
+			public void onAnimationRepeat(Animator animation) {
94
+
95
+			}
96
+		});
97
+		ObjectAnimator translationY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0, this.translationY);
98
+		translationY.setInterpolator(ACCELERATE_INTERPOLATOR);
99
+		translationY.setDuration(DURATION);
100
+		alpha.setDuration(DURATION);
101
+		set.playTogether(translationY, alpha);
102
+		set.start();
56
 	}
103
 	}
104
+
105
+	private float getWindowHeight(Context context) {
106
+		DisplayMetrics metrics = new DisplayMetrics();
107
+		WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
108
+		windowManager.getDefaultDisplay().getMetrics(metrics);
109
+		return metrics.heightPixels;
110
+	}
111
+
112
+
57
 }
113
 }

+ 36
- 17
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
+import android.animation.Animator;
3
 import android.app.Activity;
4
 import android.app.Activity;
5
+import android.graphics.Color;
6
+import android.os.Handler;
7
+import android.os.Looper;
4
 import android.support.annotation.NonNull;
8
 import android.support.annotation.NonNull;
5
 import android.view.View;
9
 import android.view.View;
6
 import android.view.ViewGroup;
10
 import android.view.ViewGroup;
11
+import android.widget.FrameLayout;
7
 import android.widget.LinearLayout;
12
 import android.widget.LinearLayout;
8
 
13
 
9
 import com.reactnativenavigation.anim.StackAnimator;
14
 import com.reactnativenavigation.anim.StackAnimator;
15
+import com.reactnativenavigation.react.ReactContainerView;
10
 import com.reactnativenavigation.utils.CompatUtils;
16
 import com.reactnativenavigation.utils.CompatUtils;
11
 import com.reactnativenavigation.views.TopBar;
17
 import com.reactnativenavigation.views.TopBar;
12
 
18
 
13
 import java.util.Collection;
19
 import java.util.Collection;
20
+import java.util.Random;
14
 
21
 
15
 public class StackController extends ParentController {
22
 public class StackController extends ParentController {
23
+
16
 	private final IdStack<ViewController> stack = new IdStack<>();
24
 	private final IdStack<ViewController> stack = new IdStack<>();
17
 	private final StackAnimator animator;
25
 	private final StackAnimator animator;
18
 	private TopBar topBar;
26
 	private TopBar topBar;
27
+	private FrameLayout container;
19
 
28
 
20
 	public StackController(final Activity activity, String id) {
29
 	public StackController(final Activity activity, String id) {
21
 		this(activity, id, new StackAnimator(activity));
30
 		this(activity, id, new StackAnimator(activity));
31
 
40
 
32
 		child.setParentStackController(this);
41
 		child.setParentStackController(this);
33
 		stack.push(child.getId(), child);
42
 		stack.push(child.getId(), child);
43
+		View enteringView = child.getView();
44
+		getContainer().addView(enteringView);
34
 
45
 
35
-		getView().addView(child.getView());
36
-//TODO animate only when needed
46
+		//TODO animatePush only when needed
37
 		if (previousTop != null) {
47
 		if (previousTop != null) {
38
-			animator.animatePush(child.getView(), previousTop.getView(), new Runnable() {
48
+			animator.animatePush(enteringView, new StackAnimator.StackAnimationListener() {
39
 				@Override
49
 				@Override
40
-				public void run() {
41
-					getView().removeView(previousTop.getView());
50
+				public void onAnimationEnd() {
51
+					getContainer().removeView(previousTop.getView());
42
 				}
52
 				}
43
 			});
53
 			});
44
 		}
54
 		}
54
 		final ViewController poppedTop = stack.pop();
64
 		final ViewController poppedTop = stack.pop();
55
 		ViewController newTop = peek();
65
 		ViewController newTop = peek();
56
 
66
 
57
-		final View enteringView = newTop.getView();
67
+		View enteringView = newTop.getView();
58
 		final View exitingView = poppedTop.getView();
68
 		final View exitingView = poppedTop.getView();
59
-
60
-		getView().addView(enteringView);
61
-
62
-		//TODO animate only when needed
63
-//		animator.animatePop(enteringView, exitingView, new Runnable() {
64
-//			@Override
65
-//			public void run() {
66
-		getView().removeView(exitingView);
67
-		poppedTop.destroy();
68
-//			}
69
-//		});
69
+		getContainer().addView(enteringView, getContainer().getChildCount() - 1);
70
+
71
+		//TODO animatePush only when needed
72
+		animator.animatePop(exitingView, new StackAnimator.StackAnimationListener() {
73
+			@Override
74
+			public void onAnimationEnd() {
75
+				getContainer().removeView(exitingView);
76
+				poppedTop.destroy();
77
+			}
78
+		});
70
 	}
79
 	}
71
 
80
 
72
 	public void popSpecific(final ViewController childController) {
81
 	public void popSpecific(final ViewController childController) {
123
 		topBar = new TopBar(getActivity());
132
 		topBar = new TopBar(getActivity());
124
 		topBar.setId(CompatUtils.generateViewId());
133
 		topBar.setId(CompatUtils.generateViewId());
125
 		root.addView(topBar);
134
 		root.addView(topBar);
135
+		container = new FrameLayout(getActivity());
136
+		container.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
137
+		root.addView(container);
126
 		return root;
138
 		return root;
127
 	}
139
 	}
128
 
140
 
136
 		ensureViewIsCreated();
148
 		ensureViewIsCreated();
137
 		return topBar;
149
 		return topBar;
138
 	}
150
 	}
151
+
152
+	private ViewGroup getContainer() {
153
+		if (container == null) {
154
+			getView();
155
+		}
156
+		return container;
157
+	}
139
 }
158
 }

+ 4
- 4
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestStackAnimator.java View File

14
 	}
14
 	}
15
 
15
 
16
 	@Override
16
 	@Override
17
-	public void animatePush(final View enteringView, final View exitingView, final Runnable onComplete) {
18
-		if (onComplete != null) onComplete.run();
17
+	public void animatePush(final View enteringView, StackAnimationListener animationListener) {
18
+		if (animationListener != null) animationListener.onAnimationEnd();
19
 	}
19
 	}
20
 
20
 
21
 	@Override
21
 	@Override
22
-	public void animatePop(final View enteringView, final View exitingView, @Nullable final Runnable onComplete) {
23
-		if (onComplete != null) onComplete.run();
22
+	public void animatePop(final View enteringView, StackAnimationListener animationListener) {
23
+		if (animationListener != null) animationListener.onAnimationEnd();
24
 	}
24
 	}
25
 }
25
 }