Selaa lähdekoodia

Add push and pop screen transition

This commit is the first step in adding proper screen transition
animations to push and pop actions.
Guy Carmeli 8 vuotta sitten
vanhempi
commit
187144675e

+ 14
- 7
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java Näytä tiedosto

9
 import com.reactnativenavigation.params.ScreenParams;
9
 import com.reactnativenavigation.params.ScreenParams;
10
 import com.reactnativenavigation.params.TitleBarButtonParams;
10
 import com.reactnativenavigation.params.TitleBarButtonParams;
11
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
11
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
12
+import com.reactnativenavigation.screens.ScreenAnimator;
12
 import com.reactnativenavigation.screens.ScreenStack;
13
 import com.reactnativenavigation.screens.ScreenStack;
13
 import com.reactnativenavigation.views.BottomTabs;
14
 import com.reactnativenavigation.views.BottomTabs;
14
 
15
 
24
     private BottomTabs bottomTabs;
25
     private BottomTabs bottomTabs;
25
     private ScreenStack[] screenStacks;
26
     private ScreenStack[] screenStacks;
26
     private int currentStackIndex = 0;
27
     private int currentStackIndex = 0;
28
+    private ScreenAnimator screenAnimator;
27
 
29
 
28
     public BottomTabsLayout(AppCompatActivity activity, ActivityParams params) {
30
     public BottomTabsLayout(AppCompatActivity activity, ActivityParams params) {
29
         super(activity);
31
         super(activity);
35
 
37
 
36
     private void createLayout() {
38
     private void createLayout() {
37
         createBottomTabs();
39
         createBottomTabs();
40
+        createScreenAnimator();
38
         addBottomTabsToScreen();
41
         addBottomTabsToScreen();
39
         addScreenStacks();
42
         addScreenStacks();
40
         showInitialScreenStack();
43
         showInitialScreenStack();
47
     }
50
     }
48
 
51
 
49
     private void createAndAddScreenStack(int position) {
52
     private void createAndAddScreenStack(int position) {
50
-        ScreenStack newStack = new ScreenStack(activity, params.tabParams.get(position), this);
53
+        ScreenStack newStack = new ScreenStack(activity, params.tabParams.get(position), this, screenAnimator);
51
         screenStacks[position] = newStack;
54
         screenStacks[position] = newStack;
52
         newStack.setVisibility(INVISIBLE);
55
         newStack.setVisibility(INVISIBLE);
53
         addScreenStack(newStack);
56
         addScreenStack(newStack);
70
         bottomTabs.addTabs(params.tabParams, this);
73
         bottomTabs.addTabs(params.tabParams, this);
71
     }
74
     }
72
 
75
 
76
+    private void createScreenAnimator() {
77
+        screenAnimator = new ScreenAnimator(bottomTabs);
78
+    }
79
+
73
     private void addBottomTabsToScreen() {
80
     private void addBottomTabsToScreen() {
74
         LayoutParams lp = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
81
         LayoutParams lp = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
75
         lp.addRule(ALIGN_PARENT_BOTTOM);
82
         lp.addRule(ALIGN_PARENT_BOTTOM);
88
     @Override
95
     @Override
89
     public boolean onBackPressed() {
96
     public boolean onBackPressed() {
90
         if (getCurrentScreenStack().canPop()) {
97
         if (getCurrentScreenStack().canPop()) {
91
-            getCurrentScreenStack().pop();
98
+            getCurrentScreenStack().pop(screenAnimator);
92
             setBottomTabsStyleFromCurrentScreen();
99
             setBottomTabsStyleFromCurrentScreen();
93
             return true;
100
             return true;
94
         } else {
101
         } else {
130
 
137
 
131
     @Override
138
     @Override
132
     public void push(ScreenParams screenParams) {
139
     public void push(ScreenParams screenParams) {
133
-        getCurrentScreenStack().push(screenParams);
140
+        getCurrentScreenStack().push(screenAnimator, screenParams);
134
         bottomTabs.setStyleFromScreen(screenParams.styleParams);
141
         bottomTabs.setStyleFromScreen(screenParams.styleParams);
135
     }
142
     }
136
 
143
 
137
     @Override
144
     @Override
138
     public void pop(ScreenParams screenParams) {
145
     public void pop(ScreenParams screenParams) {
139
-        getCurrentScreenStack().pop();
146
+        getCurrentScreenStack().pop(screenAnimator);
140
         setBottomTabsStyleFromCurrentScreen();
147
         setBottomTabsStyleFromCurrentScreen();
141
     }
148
     }
142
 
149
 
143
     @Override
150
     @Override
144
     public void popToRoot(ScreenParams params) {
151
     public void popToRoot(ScreenParams params) {
145
-        getCurrentScreenStack().popToRoot();
152
+        getCurrentScreenStack().popToRoot(screenAnimator);
146
         setBottomTabsStyleFromCurrentScreen();
153
         setBottomTabsStyleFromCurrentScreen();
147
     }
154
     }
148
 
155
 
152
         currentScreenStack.destroy();
159
         currentScreenStack.destroy();
153
         removeView(currentScreenStack);
160
         removeView(currentScreenStack);
154
 
161
 
155
-        ScreenStack newStack = new ScreenStack(activity, params, this);
162
+        ScreenStack newStack = new ScreenStack(activity, params, this, screenAnimator);
156
         screenStacks[currentStackIndex] = newStack;
163
         screenStacks[currentStackIndex] = newStack;
157
         addView(newStack, 0, new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
164
         addView(newStack, 0, new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
158
 
165
 
198
     @Override
205
     @Override
199
     public boolean onTitleBarBackPress() {
206
     public boolean onTitleBarBackPress() {
200
         if (getCurrentScreenStack().canPop()) {
207
         if (getCurrentScreenStack().canPop()) {
201
-            getCurrentScreenStack().pop();
208
+            getCurrentScreenStack().pop(screenAnimator);
202
             setBottomTabsStyleFromCurrentScreen();
209
             setBottomTabsStyleFromCurrentScreen();
203
             return true;
210
             return true;
204
         }
211
         }

+ 12
- 5
android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java Näytä tiedosto

7
 import com.reactnativenavigation.params.ScreenParams;
7
 import com.reactnativenavigation.params.ScreenParams;
8
 import com.reactnativenavigation.params.TitleBarButtonParams;
8
 import com.reactnativenavigation.params.TitleBarButtonParams;
9
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
9
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
10
+import com.reactnativenavigation.screens.ScreenAnimator;
10
 import com.reactnativenavigation.screens.ScreenStack;
11
 import com.reactnativenavigation.screens.ScreenStack;
11
 import com.reactnativenavigation.views.TitleBarBackButtonListener;
12
 import com.reactnativenavigation.views.TitleBarBackButtonListener;
12
 
13
 
19
     private final AppCompatActivity activity;
20
     private final AppCompatActivity activity;
20
     private final ScreenParams screenParams;
21
     private final ScreenParams screenParams;
21
     private ScreenStack stack;
22
     private ScreenStack stack;
23
+    private ScreenAnimator screenAnimator;
22
     private TitleBarBackButtonListener titleBarBackButtonListener;
24
     private TitleBarBackButtonListener titleBarBackButtonListener;
23
 
25
 
24
     public SingleScreenLayout(AppCompatActivity activity, ScreenParams screenParams, TitleBarBackButtonListener titleBarBackButtonListener) {
26
     public SingleScreenLayout(AppCompatActivity activity, ScreenParams screenParams, TitleBarBackButtonListener titleBarBackButtonListener) {
30
         super(activity);
32
         super(activity);
31
         this.activity = activity;
33
         this.activity = activity;
32
         this.screenParams = screenParams;
34
         this.screenParams = screenParams;
35
+        createScreenAnimator();
33
         createStack();
36
         createStack();
34
     }
37
     }
35
 
38
 
39
+    private void createScreenAnimator() {
40
+        screenAnimator = new ScreenAnimator();
41
+    }
42
+
36
     private void createStack() {
43
     private void createStack() {
37
         if (stack != null) {
44
         if (stack != null) {
38
             stack.destroy();
45
             stack.destroy();
39
             removeView(stack);
46
             removeView(stack);
40
         }
47
         }
41
-        stack = new ScreenStack(activity, screenParams, this);
48
+        stack = new ScreenStack(activity, screenParams, this, screenAnimator);
42
         addView(stack, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
49
         addView(stack, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
43
     }
50
     }
44
 
51
 
45
     @Override
52
     @Override
46
     public boolean onBackPressed() {
53
     public boolean onBackPressed() {
47
         if (stack.canPop()) {
54
         if (stack.canPop()) {
48
-            stack.pop();
55
+            stack.pop(screenAnimator);
49
             return true;
56
             return true;
50
         } else {
57
         } else {
51
             return false;
58
             return false;
60
 
67
 
61
     @Override
68
     @Override
62
     public void push(ScreenParams params) {
69
     public void push(ScreenParams params) {
63
-        stack.push(params);
70
+        stack.push(screenAnimator, params);
64
     }
71
     }
65
 
72
 
66
     @Override
73
     @Override
67
     public void pop(ScreenParams params) {
74
     public void pop(ScreenParams params) {
68
-        stack.pop();
75
+        stack.pop(screenAnimator);
69
     }
76
     }
70
 
77
 
71
     @Override
78
     @Override
72
     public void popToRoot(ScreenParams params) {
79
     public void popToRoot(ScreenParams params) {
73
-        stack.popToRoot();
80
+        stack.popToRoot(screenAnimator);
74
     }
81
     }
75
 
82
 
76
     @Override
83
     @Override

+ 110
- 0
android/app/src/main/java/com/reactnativenavigation/screens/ScreenAnimator.java Näytä tiedosto

1
+package com.reactnativenavigation.screens;
2
+
3
+import android.animation.Animator;
4
+import android.animation.AnimatorListenerAdapter;
5
+import android.animation.AnimatorSet;
6
+import android.animation.ObjectAnimator;
7
+import android.view.View;
8
+import android.view.animation.AccelerateInterpolator;
9
+import android.view.animation.DecelerateInterpolator;
10
+import android.view.animation.LinearInterpolator;
11
+
12
+import com.reactnativenavigation.utils.ViewUtils;
13
+import com.reactnativenavigation.views.BottomTabs;
14
+
15
+public class ScreenAnimator {
16
+    private static final String TAG = "ScreenAnimator";
17
+    private BottomTabs bottomTabs;
18
+
19
+    public ScreenAnimator() {
20
+
21
+    }
22
+
23
+    public ScreenAnimator(BottomTabs bottomTabs) {
24
+        this.bottomTabs = bottomTabs;
25
+    }
26
+
27
+    public void show(Screen screenToShow, Runnable onScreenRemoved) {
28
+        createPushAnimator(screenToShow, onScreenRemoved).start();
29
+    }
30
+
31
+    public void show(Screen screenToShow) {
32
+        createPushAnimator(screenToShow).start();
33
+    }
34
+
35
+    public void hide(Screen screenToHide, Runnable onScreenRemoved) {
36
+        createPopAnimator(screenToHide, onScreenRemoved).start();
37
+    }
38
+
39
+    private Animator createPushAnimator(final Screen screen) {
40
+        ObjectAnimator alpha = ObjectAnimator.ofFloat(screen, View.ALPHA, 0.7f, 1);
41
+        alpha.setStartDelay(100);
42
+        alpha.setInterpolator(new LinearInterpolator());
43
+        alpha.setDuration(150);
44
+
45
+        final float delta = 0.08f * ViewUtils.getScreenHeight();
46
+        ObjectAnimator translationY = ObjectAnimator.ofFloat(screen, View.TRANSLATION_Y, delta, 0);
47
+        translationY.setInterpolator(new AccelerateInterpolator());
48
+        translationY.setDuration(250);
49
+
50
+        AnimatorSet set = new AnimatorSet();
51
+        set.playTogether(translationY, alpha);
52
+        set.addListener(new AnimatorListenerAdapter() {
53
+            @Override
54
+            public void onAnimationStart(Animator animation) {
55
+                screen.setVisibility(View.VISIBLE);
56
+            }
57
+        });
58
+        return set;
59
+    }
60
+
61
+    private Animator createPushAnimator(final Screen screenToShow, final Runnable onScreenRemoved) {
62
+        final float translationYValue = 0.08f * ViewUtils.getScreenHeight();
63
+
64
+        ObjectAnimator alpha = ObjectAnimator.ofFloat(screenToShow, View.ALPHA, 0, 1);
65
+        alpha.setInterpolator(new DecelerateInterpolator());
66
+        alpha.setDuration(200);
67
+
68
+        ObjectAnimator translationY = ObjectAnimator.ofFloat(screenToShow, View.TRANSLATION_Y, translationYValue, 0);
69
+        translationY.setInterpolator(new DecelerateInterpolator());
70
+        translationY.setDuration(280);
71
+
72
+        AnimatorSet set = new AnimatorSet();
73
+        set.playTogether(translationY, alpha);
74
+        set.addListener(new AnimatorListenerAdapter() {
75
+            @Override
76
+            public void onAnimationStart(Animator animation) {
77
+                screenToShow.setVisibility(View.VISIBLE);
78
+            }
79
+
80
+            @Override
81
+            public void onAnimationEnd(Animator animation) {
82
+                onScreenRemoved.run();
83
+            }
84
+        });
85
+        return set;
86
+    }
87
+
88
+    private Animator createPopAnimator(final Screen screenToHide, final Runnable onScreenRemoved) {
89
+        final float translationYValue = 0.08f * ViewUtils.getScreenHeight();
90
+
91
+        ObjectAnimator alpha = ObjectAnimator.ofFloat(screenToHide, View.ALPHA, 0);
92
+        alpha.setInterpolator(new LinearInterpolator());
93
+        alpha.setStartDelay(100);
94
+        alpha.setDuration(150);
95
+
96
+        ObjectAnimator translationY = ObjectAnimator.ofFloat(screenToHide, View.TRANSLATION_Y, translationYValue);
97
+        translationY.setInterpolator(new AccelerateInterpolator());
98
+        translationY.setDuration(250);
99
+
100
+        AnimatorSet set = new AnimatorSet();
101
+        set.playTogether(translationY, alpha);
102
+        set.addListener(new AnimatorListenerAdapter() {
103
+            @Override
104
+            public void onAnimationEnd(Animator animation) {
105
+                onScreenRemoved.run();
106
+            }
107
+        });
108
+        return set;
109
+    }
110
+}

+ 34
- 20
android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java Näytä tiedosto

1
 package com.reactnativenavigation.screens;
1
 package com.reactnativenavigation.screens;
2
 
2
 
3
-import android.animation.LayoutTransition;
4
 import android.support.v7.app.AppCompatActivity;
3
 import android.support.v7.app.AppCompatActivity;
5
 import android.view.ViewManager;
4
 import android.view.ViewManager;
6
 import android.widget.FrameLayout;
5
 import android.widget.FrameLayout;
24
     private TitleBarBackButtonListener titleBarBackButtonListener;
23
     private TitleBarBackButtonListener titleBarBackButtonListener;
25
     private Stack<Screen> stack = new Stack<>();
24
     private Stack<Screen> stack = new Stack<>();
26
 
25
 
27
-    public ScreenStack(AppCompatActivity activity, ScreenParams initialScreenParams, TitleBarBackButtonListener titleBarBackButtonListener) {
26
+    public ScreenStack(AppCompatActivity activity,
27
+                       ScreenParams initialScreenParams,
28
+                       TitleBarBackButtonListener titleBarBackButtonListener,
29
+                       ScreenAnimator screenAnimator) {
28
         super(activity);
30
         super(activity);
29
         this.activity = activity;
31
         this.activity = activity;
30
         this.titleBarBackButtonListener = titleBarBackButtonListener;
32
         this.titleBarBackButtonListener = titleBarBackButtonListener;
31
-        setLayoutTransition(new LayoutTransition());
32
-        pushInitialScreen(initialScreenParams);
33
+//        setLayoutTransition(new LayoutTransition());
34
+        pushInitialScreen(screenAnimator, initialScreenParams);
33
     }
35
     }
34
 
36
 
35
-    private void pushInitialScreen(ScreenParams initialScreenParams) {
36
-        addScreen(initialScreenParams);
37
+    private void pushInitialScreen(ScreenAnimator screenAnimator, ScreenParams initialScreenParams) {
38
+        Screen initialScreen = ScreenFactory.create(activity, initialScreenParams, titleBarBackButtonListener);
39
+        addScreen(initialScreen);
40
+        screenAnimator.show(initialScreen);
37
     }
41
     }
38
 
42
 
39
-    public void push(ScreenParams screenParams) {
40
-        Screen previous = stack.peek();
41
-        addScreen(screenParams);
42
-        removePreviousWithoutUnmount(previous);
43
+    public void push(ScreenAnimator screenAnimator, ScreenParams params) {
44
+        Screen nextScreen = ScreenFactory.create(activity, params, titleBarBackButtonListener);
45
+        final Screen previousScreen = stack.peek();
46
+        addScreen(nextScreen);
47
+        screenAnimator.show(nextScreen, new Runnable() {
48
+            @Override
49
+            public void run() {
50
+                removePreviousWithoutUnmount(previousScreen);
51
+            }
52
+        });
43
     }
53
     }
44
 
54
 
45
-    private void addScreen(ScreenParams screenParams) {
46
-        Screen screen = ScreenFactory.create(activity, screenParams, titleBarBackButtonListener);
55
+    private void addScreen(Screen screen) {
56
+        screen.setVisibility(INVISIBLE);
47
         addView(screen, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
57
         addView(screen, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
48
         stack.push(screen);
58
         stack.push(screen);
49
     }
59
     }
53
         removeView(previous);
63
         removeView(previous);
54
     }
64
     }
55
 
65
 
56
-    public void pop() {
66
+    public void pop(ScreenAnimator screenAnimator) {
57
         if (!canPop()) {
67
         if (!canPop()) {
58
             return;
68
             return;
59
         }
69
         }
60
 
70
 
61
-        Screen toRemove = stack.pop();
71
+        final Screen toRemove = stack.pop();
62
         Screen previous = stack.peek();
72
         Screen previous = stack.peek();
63
 
73
 
64
         readdPrevious(previous);
74
         readdPrevious(previous);
65
-
66
-        toRemove.ensureUnmountOnDetachedFromWindow();
67
-        removeView(toRemove);
75
+        screenAnimator.hide(toRemove, new Runnable() {
76
+            @Override
77
+            public void run() {
78
+                toRemove.ensureUnmountOnDetachedFromWindow();
79
+                removeView(toRemove);
80
+            }
81
+        });
68
     }
82
     }
69
 
83
 
70
     private void readdPrevious(Screen previous) {
84
     private void readdPrevious(Screen previous) {
71
-        addView(previous, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
85
+        addView(previous, 0, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
72
         previous.preventMountAfterReattachedToWindow();
86
         previous.preventMountAfterReattachedToWindow();
73
     }
87
     }
74
 
88
 
75
-    public void popToRoot() {
89
+    public void popToRoot(ScreenAnimator screenAnimator) {
76
         while (canPop()) {
90
         while (canPop()) {
77
-            pop();
91
+            pop(screenAnimator);
78
         }
92
         }
79
     }
93
     }
80
 
94
 

+ 10
- 0
android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java Näytä tiedosto

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
+import android.content.Context;
3
 import android.graphics.Color;
4
 import android.graphics.Color;
4
 import android.graphics.PorterDuff;
5
 import android.graphics.PorterDuff;
5
 import android.graphics.PorterDuffColorFilter;
6
 import android.graphics.PorterDuffColorFilter;
6
 import android.graphics.drawable.Drawable;
7
 import android.graphics.drawable.Drawable;
8
+import android.util.DisplayMetrics;
7
 import android.view.View;
9
 import android.view.View;
8
 import android.view.ViewTreeObserver;
10
 import android.view.ViewTreeObserver;
11
+import android.view.WindowManager;
9
 
12
 
10
 import com.reactnativenavigation.NavigationApplication;
13
 import com.reactnativenavigation.NavigationApplication;
11
 
14
 
40
     public static int generateViewId() {
43
     public static int generateViewId() {
41
         return viewId.incrementAndGet();
44
         return viewId.incrementAndGet();
42
     }
45
     }
46
+
47
+    public static float getScreenHeight() {
48
+        WindowManager wm = (WindowManager) NavigationApplication.instance.getSystemService(Context.WINDOW_SERVICE);
49
+        DisplayMetrics metrics = new DisplayMetrics();
50
+        wm.getDefaultDisplay().getMetrics(metrics);
51
+        return metrics.heightPixels;
52
+    }
43
 }
53
 }
44
 
54