Browse Source

Add fab to example project

Guy Carmeli 8 years ago
parent
commit
6a5c53b359

+ 112
- 0
android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonAnimator.java View File

@@ -0,0 +1,112 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.animation.Animator;
4
+import android.animation.AnimatorListenerAdapter;
5
+import android.support.design.widget.FloatingActionButton;
6
+import android.view.View;
7
+
8
+import java.util.List;
9
+
10
+public class FloatingActionButtonAnimator {
11
+
12
+    private final FloatingActionButton collapsedFab;
13
+    private final FloatingActionButton expendedFab;
14
+    private int crossFadeAnimationDuration;
15
+
16
+    private enum State{Showing, Idle, Removing}
17
+    private State state = State.Idle;
18
+
19
+    public FloatingActionButtonAnimator(FloatingActionButton collapsedFab, FloatingActionButton expendedFab, int crossFadeAnimationDuration) {
20
+        this.collapsedFab = collapsedFab;
21
+        this.expendedFab = expendedFab;
22
+        this.crossFadeAnimationDuration = crossFadeAnimationDuration;
23
+    }
24
+
25
+    boolean isAnimating() {
26
+        return state == State.Showing || state == State.Removing;
27
+    }
28
+
29
+    void show() {
30
+        state = State.Showing;
31
+        collapsedFab.setScaleX(0);
32
+        collapsedFab.setScaleY(0);
33
+        collapsedFab.animate()
34
+                .alpha(1)
35
+                .scaleX(1)
36
+                .scaleY(1)
37
+                .setListener(new AnimatorListenerAdapter() {
38
+                    @Override
39
+                    public void onAnimationEnd(Animator animation) {
40
+                        state = State.Idle;
41
+                    }
42
+                })
43
+                .setDuration(crossFadeAnimationDuration)
44
+                .start();
45
+    }
46
+
47
+    void hideCollapsed() {
48
+        animateFab(collapsedFab, 0, 90);
49
+    }
50
+
51
+    void showExpended() {
52
+        animateFab(expendedFab, 1, 0);
53
+    }
54
+
55
+    void showCollapsed() {
56
+        animateFab(collapsedFab, 1, 0);
57
+    }
58
+
59
+    void hideExpended() {
60
+        animateFab(expendedFab, 0, -90);
61
+    }
62
+
63
+    private void animateFab(final FloatingActionButton fab, final int alpha, int rotation) {
64
+        fab.animate()
65
+                .alpha(alpha)
66
+                .setDuration(crossFadeAnimationDuration)
67
+                .rotation(rotation)
68
+                .setListener(new AnimatorListenerAdapter() {
69
+                    @Override
70
+                    public void onAnimationStart(Animator animation) {
71
+                        if (fab.getVisibility() == View.GONE) {
72
+                            fab.setVisibility(View.VISIBLE);
73
+                        }
74
+                    }
75
+
76
+                    @Override
77
+                    public void onAnimationEnd(Animator animation) {
78
+                        fab.setVisibility(alpha == 0 ? View.GONE : View.VISIBLE);
79
+                    }
80
+                })
81
+                .start();
82
+    }
83
+
84
+    void removeFabFromScreen(FloatingActionButton fab, final AnimatorListenerAdapter animationListener) {
85
+        state = State.Removing;
86
+        fab.animate()
87
+                .alpha(0)
88
+                .scaleX(0)
89
+                .scaleY(0)
90
+                .setDuration(crossFadeAnimationDuration)
91
+                .setListener(new AnimatorListenerAdapter() {
92
+                    @Override
93
+                    public void onAnimationEnd(Animator animation) {
94
+                        if (animationListener != null) {
95
+                            animationListener.onAnimationEnd(animation);
96
+                        }
97
+                    }
98
+                })
99
+                .start();
100
+    }
101
+
102
+    void removeActionsFromScreen(List<FloatingActionButton> actions) {
103
+        for (FloatingActionButton action : actions) {
104
+            action.animate()
105
+                    .alpha(0)
106
+                    .scaleX(0)
107
+                    .scaleY(0)
108
+                    .setDuration(crossFadeAnimationDuration)
109
+                    .start();
110
+        }
111
+    }
112
+}

+ 11
- 82
android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonCoordinator.java View File

@@ -30,6 +30,7 @@ public class FloatingActionButtonCoordinator {
30 30
     private final int crossFadeAnimationDuration;
31 31
     private final int actionSize;
32 32
     final int margin = (int) ViewUtils.convertDpToPixel(16);
33
+    FloatingActionButtonAnimator fabAnimator;
33 34
     private final ArrayList<FloatingActionButton> actions;
34 35
 
35 36
     public FloatingActionButtonCoordinator(CoordinatorLayout parent) {
@@ -44,22 +45,19 @@ public class FloatingActionButtonCoordinator {
44 45
         createCollapsedFab();
45 46
         createExpendedFab();
46 47
         setStyle();
47
-        show();
48
-    }
49
-
50
-    public void remove() {
51
-        remove(null);
48
+        fabAnimator = new FloatingActionButtonAnimator(collapsedFab, expendedFab, crossFadeAnimationDuration);
49
+        fabAnimator.show();
52 50
     }
53 51
 
54 52
     public void remove(@Nullable final Runnable onComplete) {
55
-        if (parent.getChildCount() == 0) {
53
+        if (parent.getChildCount() == 0 || fabAnimator.isAnimating()) {
56 54
             if (onComplete != null) {
57 55
                 onComplete.run();
58 56
             }
59 57
             return;
60 58
         }
61 59
 
62
-        removeFabFromScreen(expendedFab, new AnimatorListenerAdapter() {
60
+        fabAnimator.removeFabFromScreen(expendedFab, new AnimatorListenerAdapter() {
63 61
             @Override
64 62
             public void onAnimationEnd(Animator animation) {
65 63
                 removeAllViews();
@@ -68,29 +66,8 @@ public class FloatingActionButtonCoordinator {
68 66
                 }
69 67
             }
70 68
         });
71
-        removeFabFromScreen(collapsedFab, null);
72
-        removeActionsFromScreen();
73
-    }
74
-
75
-    private void removeActionsFromScreen() {
76
-        for (FloatingActionButton action : actions) {
77
-            action.animate()
78
-                    .alpha(0)
79
-                    .scaleX(0)
80
-                    .scaleY(0)
81
-                    .setDuration(crossFadeAnimationDuration)
82
-                    .start();
83
-        }
84
-    }
85
-
86
-    private void removeFabFromScreen(FloatingActionButton fab, AnimatorListenerAdapter animationListener) {
87
-        fab.animate()
88
-                .alpha(0)
89
-                .scaleX(0)
90
-                .scaleY(0)
91
-                .setDuration(crossFadeAnimationDuration)
92
-                .setListener(animationListener)
93
-                .start();
69
+        fabAnimator.removeFabFromScreen(collapsedFab, null);
70
+        fabAnimator.removeActionsFromScreen(actions);
94 71
     }
95 72
 
96 73
     private void removeAllViews() {
@@ -110,8 +87,8 @@ public class FloatingActionButtonCoordinator {
110 87
         collapsedFab.setOnClickListener(new View.OnClickListener() {
111 88
             @Override
112 89
             public void onClick(View v) {
113
-                hideCollapsed();
114
-                showExpended();
90
+                fabAnimator.hideCollapsed();
91
+                fabAnimator.showExpended();
115 92
                 showActions();
116 93
             }
117 94
         });
@@ -125,8 +102,8 @@ public class FloatingActionButtonCoordinator {
125 102
         expendedFab.setOnClickListener(new View.OnClickListener() {
126 103
             @Override
127 104
             public void onClick(View v) {
128
-                hideExpended();
129
-                showCollapsed();
105
+                fabAnimator.hideExpended();
106
+                fabAnimator.showCollapsed();
130 107
             }
131 108
         });
132 109
     }
@@ -138,43 +115,6 @@ public class FloatingActionButtonCoordinator {
138 115
         return fab;
139 116
     }
140 117
 
141
-    private void hideCollapsed() {
142
-        animateFab(collapsedFab, 0, 90);
143
-    }
144
-
145
-    private void showExpended() {
146
-        animateFab(expendedFab, 1, 0);
147
-    }
148
-
149
-    private void showCollapsed() {
150
-        animateFab(collapsedFab, 1, 0);
151
-    }
152
-
153
-    private void hideExpended() {
154
-        animateFab(expendedFab, 0, -90);
155
-    }
156
-
157
-    private void animateFab(final FloatingActionButton fab, final int alpha, int rotation) {
158
-        fab.animate()
159
-                .alpha(alpha)
160
-                .setDuration(crossFadeAnimationDuration)
161
-                .rotation(rotation)
162
-                .setListener(new AnimatorListenerAdapter() {
163
-                    @Override
164
-                    public void onAnimationStart(Animator animation) {
165
-                        if (fab.getVisibility() == View.GONE) {
166
-                            fab.setVisibility(View.VISIBLE);
167
-                        }
168
-                    }
169
-
170
-                    @Override
171
-                    public void onAnimationEnd(Animator animation) {
172
-                        fab.setVisibility(alpha == 0 ? View.GONE : View.VISIBLE);
173
-                    }
174
-                })
175
-                .start();
176
-    }
177
-
178 118
     private CoordinatorLayout.LayoutParams createFabLayoutParams() {
179 119
         final CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
180 120
         lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
@@ -189,17 +129,6 @@ public class FloatingActionButtonCoordinator {
189 129
         expendedFab.setBackgroundTintList(ColorStateList.valueOf(params.backgroundColor.getColor()));
190 130
     }
191 131
 
192
-    private void show() {
193
-        collapsedFab.setScaleX(0);
194
-        collapsedFab.setScaleY(0);
195
-        collapsedFab.animate()
196
-                .alpha(1)
197
-                .scaleX(1)
198
-                .scaleY(1)
199
-                .setDuration(crossFadeAnimationDuration)
200
-                .start();
201
-    }
202
-
203 132
     private void showActions() {
204 133
         if (actions.size() > 0) {
205 134
             return;

BIN
example-redux/img/ic_clear@1.5x.png View File


BIN
example-redux/img/ic_clear@1x.png View File


BIN
example-redux/img/ic_clear@2x.png View File


BIN
example-redux/img/ic_clear@3x.png View File


BIN
example-redux/img/ic_clear@4x.png View File


BIN
example-redux/img/ic_mail@1.5.png View File


BIN
example-redux/img/ic_mail@1x.png View File


BIN
example-redux/img/ic_mail@2x.png View File


BIN
example-redux/img/ic_mail@3x.png View File


BIN
example-redux/img/ic_mail@4x.png View File


BIN
example-redux/img/ic_share@1.5x.png View File


BIN
example-redux/img/ic_share@1x.png View File


BIN
example-redux/img/ic_share@2x.png View File


BIN
example-redux/img/ic_share@3x.png View File


BIN
example-redux/img/ic_share@4x.png View File


+ 66
- 66
example-redux/src/app.js View File

@@ -35,74 +35,74 @@ export default class App {
35 35
   startApp(root) {
36 36
     switch (root) {
37 37
       case 'login':
38
-        Navigation.startSingleScreenApp({
39
-         screen: {
40
-           screen: 'example.LoginScreen',
41
-           title: 'Login',
42
-           navigatorStyle: {}
43
-         },
44
-         passProps: {
45
-           str: 'This is a prop passed in \'startSingleScreenApp()\'!',
46
-           obj: {
47
-             str: 'This is a prop passed in an object!',
48
-             arr: [
49
-               {
50
-                 str: 'This is a prop in an object in an array in an object!'
51
-               }
52
-             ],
53
-             arr2: [
54
-               [
55
-                 'array of strings',
56
-                 'with two strings'
57
-               ],
58
-               [
59
-                 1, 2, 3
60
-               ]
61
-             ]
62
-           },
63
-           num: 1234,
64
-           fn: function() {
65
-             return 'Hello from a function!';
66
-           }
67
-         }
68
-        });
69 38
         // Navigation.startSingleScreenApp({
70
-        //   screen: {
71
-        //     screen: 'example.FirstTabScreen',
72
-        //     title: 'Login',
73
-        //     topTabs: [
74
-        //       {
75
-        //         screenId: 'example.FirstTabScreen',
76
-        //         title: 'Tab1',
77
-        //         passProps: {
78
-        //           str: 'This is a prop passed to Tab4',
79
-        //           fn: () => 'Hello from a function passed as passProps!'
80
-        //         }
81
-        //       },
82
-        //       {
83
-        //         screenId: 'example.PushedScreen',
84
-        //         title: 'Tab3',
85
-        //         passProps: {
86
-        //           str: 'This is a prop passed to Tab2'
87
-        //         }
88
-        //       },
89
-        //       {
90
-        //         screenId: 'example.ListScreen',
91
-        //         title: 'Tab2',
92
-        //         passProps: {
93
-        //           str: 'This is a prop passed to Tab1'
94
-        //         }
95
-        //       }
96
-        //     ],
97
-        //     navigatorStyle: {}
98
-        //   },
99
-        //   drawer: { // optional, add this if you want a side menu drawer in your app
100
-        //     left: { // optional, define if you want a drawer from the left
101
-        //       screen: 'example.SideMenu' // unique ID registered with Navigation.registerScreen
102
-        //     },
103
-        //     disableOpenGesture: false // optional, can the drawer be opened with a swipe instead of button
104
-        //   }
39
+        //  screen: {
40
+        //    screen: 'example.LoginScreen',
41
+        //    title: 'Login',
42
+        //    navigatorStyle: {}
43
+        //  },
44
+        //  passProps: {
45
+        //    str: 'This is a prop passed in \'startSingleScreenApp()\'!',
46
+        //    obj: {
47
+        //      str: 'This is a prop passed in an object!',
48
+        //      arr: [
49
+        //        {
50
+        //          str: 'This is a prop in an object in an array in an object!'
51
+        //        }
52
+        //      ],
53
+        //      arr2: [
54
+        //        [
55
+        //          'array of strings',
56
+        //          'with two strings'
57
+        //        ],
58
+        //        [
59
+        //          1, 2, 3
60
+        //        ]
61
+        //      ]
62
+        //    },
63
+        //    num: 1234,
64
+        //    fn: function() {
65
+        //      return 'Hello from a function!';
66
+        //    }
67
+        //  }
105 68
         // });
69
+        Navigation.startSingleScreenApp({
70
+          screen: {
71
+            title: 'Example',
72
+            screen: 'example.TopTabsScreen',
73
+            topTabs: [
74
+              {
75
+                screenId: 'example.FirstTabScreen',
76
+                title: 'Tab1',
77
+                passProps: {
78
+                  str: 'This is a prop passed to Tab1',
79
+                  fn: () => 'Hello from a function passed as passProps!'
80
+                }
81
+              },
82
+              {
83
+                screenId: 'example.PushedScreen',
84
+                title: 'Tab2',
85
+                passProps: {
86
+                  str: 'This is a prop passed to Tab2'
87
+                }
88
+              },
89
+              {
90
+                screenId: 'example.ListScreen',
91
+                title: 'Tab3',
92
+                passProps: {
93
+                  str: 'This is a prop passed to Tab3'
94
+                }
95
+              }
96
+            ],
97
+            navigatorStyle: {}
98
+          },
99
+          drawer: { // optional, add this if you want a side menu drawer in your app
100
+            left: { // optional, define if you want a drawer from the left
101
+              screen: 'example.SideMenu' // unique ID registered with Navigation.registerScreen
102
+            },
103
+            disableOpenGesture: false // optional, can the drawer be opened with a swipe instead of button
104
+          }
105
+        });
106 106
         return;
107 107
       case 'after-login':
108 108
         Navigation.startTabBasedApp({

+ 30
- 1
example-redux/src/screens/FirstTabScreen.js View File

@@ -38,7 +38,36 @@ class FirstTabScreen extends Component {
38 38
         title: 'Add',
39 39
         id: 'add'
40 40
       }
41
-    ]
41
+    ],
42
+    fab: {
43
+      id: 'share',
44
+      collapsedIcon: require('../../img/ic_share.png'),
45
+      expendedIcon: require('../../img/ic_clear.png'),
46
+      backgroundColor: '#3F51B5',
47
+      actions: [
48
+        {
49
+          id: 'mail',
50
+          icon: require('../../img/ic_mail.png'),
51
+          backgroundColor: '#03A9F4'
52
+        },
53
+        {
54
+          id: 'action2',
55
+          icon: require('../../img/ic_home.png'),
56
+          backgroundColor: '#4CAF50'
57
+        },
58
+        {
59
+          id: 'action3',
60
+          icon: require('../../img/ic_home.png'),
61
+          backgroundColor: '#FFEB3B'
62
+        },
63
+        {
64
+          id: 'action3',
65
+          icon: require('../../img/ic_share.png'),
66
+          backgroundColor: '#FF5722'
67
+        }
68
+      ]
69
+
70
+    }
42 71
   };
43 72
 
44 73
   constructor(props) {

+ 5
- 0
example-redux/src/screens/PushedScreen.js View File

@@ -29,6 +29,11 @@ class PushedScreen extends Component {
29 29
     leftButton: {
30 30
       id: 'back',
31 31
       color: '#00ff00'
32
+    },
33
+    fab: {
34
+      id: 'share',
35
+      collapsedIcon: require('../../img/ic_home.png'),
36
+      backgroundColor: '#607D8B'
32 37
     }
33 38
   };
34 39
 

+ 8
- 0
example-redux/src/screens/SecondTabScreen.js View File

@@ -19,6 +19,14 @@ class SecondTabScreen extends Component {
19 19
     navBarTranslucent: true
20 20
   };
21 21
 
22
+  static navigatorButtons = {
23
+    fab: {
24
+      id: 'share',
25
+      collapsedIcon: require('../../img/ic_home.png'),
26
+      backgroundColor: '#607D8B'
27
+    }
28
+  };
29
+
22 30
   constructor(props) {
23 31
     super(props);
24 32
     this.buttonsCounter = 0;

+ 3
- 0
example-redux/src/screens/TopTabsScreen.js View File

@@ -0,0 +1,3 @@
1
+export default class TopTabsScreen {
2
+
3
+}

+ 2
- 0
example-redux/src/screens/index.js View File

@@ -7,6 +7,7 @@ import PushedScreen from './PushedScreen';
7 7
 import ListScreen from './ListScreen';
8 8
 import SideMenu from './SideMenu';
9 9
 import BottomTabsSideMenu from './BottomTabsSideMenu';
10
+import TopTabsScreen from './TopTabsScreen';
10 11
 
11 12
 // register all screens of the app (including internal ones)
12 13
 export function registerScreens(store, Provider) {
@@ -17,4 +18,5 @@ export function registerScreens(store, Provider) {
17 18
   Navigation.registerComponent('example.ListScreen', () => ListScreen, store, Provider);
18 19
   Navigation.registerComponent('example.SideMenu', () => SideMenu, store, Provider);
19 20
   Navigation.registerComponent('example.BottomTabsSideMenu', () => BottomTabsSideMenu, store, Provider);
21
+  Navigation.registerComponent('example.TopTabsScreen', () => TopTabsScreen);
20 22
 }