Ver código fonte

Initial LightBox implementation on Android (#978)

Guy Carmeli 7 anos atrás
pai
commit
43b1edcc1c

+ 13
- 0
android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java Ver arquivo

@@ -10,12 +10,14 @@ import com.facebook.react.bridge.ReadableMap;
10 10
 import com.reactnativenavigation.controllers.NavigationCommandsHandler;
11 11
 import com.reactnativenavigation.params.ContextualMenuParams;
12 12
 import com.reactnativenavigation.params.FabParams;
13
+import com.reactnativenavigation.params.LightBoxParams;
13 14
 import com.reactnativenavigation.params.SlidingOverlayParams;
14 15
 import com.reactnativenavigation.params.SnackbarParams;
15 16
 import com.reactnativenavigation.params.TitleBarButtonParams;
16 17
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
17 18
 import com.reactnativenavigation.params.parsers.ContextualMenuParamsParser;
18 19
 import com.reactnativenavigation.params.parsers.FabParamsParser;
20
+import com.reactnativenavigation.params.parsers.LightBoxParamsParser;
19 21
 import com.reactnativenavigation.params.parsers.SlidingOverlayParamsParser;
20 22
 import com.reactnativenavigation.params.parsers.SnackbarParamsParser;
21 23
 import com.reactnativenavigation.params.parsers.TitleBarButtonParamsParser;
@@ -169,6 +171,17 @@ public class NavigationReactModule extends ReactContextBaseJavaModule {
169 171
         NavigationCommandsHandler.showModal(BundleConverter.toBundle(params));
170 172
     }
171 173
 
174
+    @ReactMethod
175
+    public void showLightBox(final ReadableMap params) {
176
+        LightBoxParams lbp = new LightBoxParamsParser(BundleConverter.toBundle(params)).parse();
177
+        NavigationCommandsHandler.showLightBox(lbp);
178
+    }
179
+
180
+    @ReactMethod
181
+    public void dismissLightBox() {
182
+        NavigationCommandsHandler.dismissLightBox();
183
+    }
184
+
172 185
     @ReactMethod
173 186
     public void dismissAllModals() {
174 187
         NavigationCommandsHandler.dismissAllModals();

+ 9
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java Ver arquivo

@@ -26,6 +26,7 @@ import com.reactnativenavigation.params.ActivityParams;
26 26
 import com.reactnativenavigation.params.AppStyle;
27 27
 import com.reactnativenavigation.params.ContextualMenuParams;
28 28
 import com.reactnativenavigation.params.FabParams;
29
+import com.reactnativenavigation.params.LightBoxParams;
29 30
 import com.reactnativenavigation.params.ScreenParams;
30 31
 import com.reactnativenavigation.params.SlidingOverlayParams;
31 32
 import com.reactnativenavigation.params.SnackbarParams;
@@ -243,6 +244,14 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard
243 244
         modalController.dismissAllModals();
244 245
     }
245 246
 
247
+    public void showLightBox(LightBoxParams params) {
248
+        layout.showLightBox(params);
249
+    }
250
+
251
+    public void dismissLightBox() {
252
+        layout.dismissLightBox();
253
+    }
254
+
246 255
     //TODO all these setters should be combined to something like setStyle
247 256
     void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) {
248 257
         layout.setTopBarVisible(screenInstanceId, hidden, animated);

+ 30
- 3
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java Ver arquivo

@@ -9,6 +9,7 @@ import com.reactnativenavigation.NavigationApplication;
9 9
 import com.reactnativenavigation.params.ActivityParams;
10 10
 import com.reactnativenavigation.params.ContextualMenuParams;
11 11
 import com.reactnativenavigation.params.FabParams;
12
+import com.reactnativenavigation.params.LightBoxParams;
12 13
 import com.reactnativenavigation.params.ScreenParams;
13 14
 import com.reactnativenavigation.params.SlidingOverlayParams;
14 15
 import com.reactnativenavigation.params.SnackbarParams;
@@ -159,18 +160,44 @@ public class NavigationCommandsHandler {
159 160
         });
160 161
     }
161 162
 
162
-    public static void showModal(Bundle params) {
163
+    public static void showModal(final Bundle params) {
163 164
         final NavigationActivity currentActivity = NavigationActivity.currentActivity;
164 165
         if (currentActivity == null) {
165 166
             return;
166 167
         }
167 168
 
168
-        final ScreenParams screenParams = ScreenParamsParser.parse(params);
169
+        NavigationApplication.instance.runOnMainThread(new Runnable() {
170
+            @Override
171
+            public void run() {
172
+                currentActivity.showModal(ScreenParamsParser.parse(params));
173
+            }
174
+        });
175
+    }
176
+
177
+    public static void showLightBox(final LightBoxParams params) {
178
+        final NavigationActivity currentActivity = NavigationActivity.currentActivity;
179
+        if (currentActivity == null) {
180
+            return;
181
+        }
182
+
183
+        NavigationApplication.instance.runOnMainThread(new Runnable() {
184
+            @Override
185
+            public void run() {
186
+                currentActivity.showLightBox(params);
187
+            }
188
+        });
189
+    }
190
+
191
+    public static void dismissLightBox() {
192
+        final NavigationActivity currentActivity = NavigationActivity.currentActivity;
193
+        if (currentActivity == null) {
194
+            return;
195
+        }
169 196
 
170 197
         NavigationApplication.instance.runOnMainThread(new Runnable() {
171 198
             @Override
172 199
             public void run() {
173
-                currentActivity.showModal(screenParams);
200
+                currentActivity.dismissLightBox();
174 201
             }
175 202
         });
176 203
     }

+ 28
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java Ver arquivo

@@ -16,6 +16,7 @@ import com.reactnativenavigation.events.ScreenChangedEvent;
16 16
 import com.reactnativenavigation.params.ActivityParams;
17 17
 import com.reactnativenavigation.params.ContextualMenuParams;
18 18
 import com.reactnativenavigation.params.FabParams;
19
+import com.reactnativenavigation.params.LightBoxParams;
19 20
 import com.reactnativenavigation.params.ScreenParams;
20 21
 import com.reactnativenavigation.params.SideMenuParams;
21 22
 import com.reactnativenavigation.params.SlidingOverlayParams;
@@ -25,6 +26,7 @@ import com.reactnativenavigation.params.TitleBarLeftButtonParams;
25 26
 import com.reactnativenavigation.screens.Screen;
26 27
 import com.reactnativenavigation.screens.ScreenStack;
27 28
 import com.reactnativenavigation.views.BottomTabs;
29
+import com.reactnativenavigation.views.LightBox;
28 30
 import com.reactnativenavigation.views.SideMenu;
29 31
 import com.reactnativenavigation.views.SideMenu.Side;
30 32
 import com.reactnativenavigation.views.SnackbarAndFabContainer;
@@ -47,6 +49,7 @@ public class BottomTabsLayout extends BaseLayout implements AHBottomNavigation.O
47 49
     private final SlidingOverlaysQueue slidingOverlaysQueue = new SlidingOverlaysQueue();
48 50
     private @Nullable SideMenu sideMenu;
49 51
     private int currentStackIndex = 0;
52
+    private LightBox lightBox;
50 53
 
51 54
     public BottomTabsLayout(AppCompatActivity activity, ActivityParams params) {
52 55
         super(activity);
@@ -216,6 +219,27 @@ public class BottomTabsLayout extends BaseLayout implements AHBottomNavigation.O
216 219
         snackbarAndFabContainer.dismissSnackbar();
217 220
     }
218 221
 
222
+    @Override
223
+    public void showLightBox(LightBoxParams params) {
224
+        if (lightBox == null) {
225
+            lightBox = new LightBox(getActivity(), new Runnable() {
226
+                @Override
227
+                public void run() {
228
+                    lightBox = null;
229
+                }
230
+            }, params);
231
+            lightBox.show();
232
+        }
233
+    }
234
+
235
+    @Override
236
+    public void dismissLightBox() {
237
+        if (lightBox != null) {
238
+            lightBox.hide();
239
+            lightBox = null;
240
+        }
241
+    }
242
+
219 243
     @Override
220 244
     public void showSlidingOverlay(final SlidingOverlayParams params) {
221 245
         slidingOverlaysQueue.add(new SlidingOverlay(this, params));
@@ -311,6 +335,10 @@ public class BottomTabsLayout extends BaseLayout implements AHBottomNavigation.O
311 335
         if (sideMenu != null) {
312 336
             sideMenu.destroy();
313 337
         }
338
+        if (lightBox != null) {
339
+            lightBox.destroy();
340
+            lightBox = null;
341
+        }
314 342
         slidingOverlaysQueue.destroy();
315 343
     }
316 344
 

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java Ver arquivo

@@ -5,6 +5,7 @@ import android.view.View;
5 5
 import com.facebook.react.bridge.Callback;
6 6
 import com.reactnativenavigation.params.ContextualMenuParams;
7 7
 import com.reactnativenavigation.params.FabParams;
8
+import com.reactnativenavigation.params.LightBoxParams;
8 9
 import com.reactnativenavigation.params.SlidingOverlayParams;
9 10
 import com.reactnativenavigation.params.SnackbarParams;
10 11
 import com.reactnativenavigation.params.TitleBarButtonParams;
@@ -52,4 +53,8 @@ public interface Layout extends ScreenStackContainer {
52 53
     Screen getCurrentScreen();
53 54
 
54 55
     void dismissSnackbar();
56
+
57
+    void showLightBox(LightBoxParams params);
58
+
59
+    void dismissLightBox();
55 60
 }

+ 30
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java Ver arquivo

@@ -11,6 +11,7 @@ import com.reactnativenavigation.events.EventBus;
11 11
 import com.reactnativenavigation.events.ScreenChangedEvent;
12 12
 import com.reactnativenavigation.params.ContextualMenuParams;
13 13
 import com.reactnativenavigation.params.FabParams;
14
+import com.reactnativenavigation.params.LightBoxParams;
14 15
 import com.reactnativenavigation.params.ScreenParams;
15 16
 import com.reactnativenavigation.params.SideMenuParams;
16 17
 import com.reactnativenavigation.params.SlidingOverlayParams;
@@ -20,6 +21,7 @@ import com.reactnativenavigation.params.TitleBarLeftButtonParams;
20 21
 import com.reactnativenavigation.screens.Screen;
21 22
 import com.reactnativenavigation.screens.ScreenStack;
22 23
 import com.reactnativenavigation.views.LeftButtonOnClickListener;
24
+import com.reactnativenavigation.views.LightBox;
23 25
 import com.reactnativenavigation.views.SideMenu;
24 26
 import com.reactnativenavigation.views.SideMenu.Side;
25 27
 import com.reactnativenavigation.views.SnackbarAndFabContainer;
@@ -40,6 +42,7 @@ public class SingleScreenLayout extends BaseLayout {
40 42
     protected LeftButtonOnClickListener leftButtonOnClickListener;
41 43
     private @Nullable SideMenu sideMenu;
42 44
     private final SlidingOverlaysQueue slidingOverlaysQueue = new SlidingOverlaysQueue();
45
+    private LightBox lightBox;
43 46
 
44 47
     public SingleScreenLayout(AppCompatActivity activity, SideMenuParams leftSideMenuParams,
45 48
                               SideMenuParams rightSideMenuParams, ScreenParams screenParams) {
@@ -124,6 +127,12 @@ public class SingleScreenLayout extends BaseLayout {
124 127
         if (sideMenu != null) {
125 128
             sideMenu.destroy();
126 129
         }
130
+        if (sideMenu != null) {
131
+            sideMenu.destroy();
132
+        }
133
+        if (lightBox != null) {
134
+            lightBox.destroy();
135
+        }
127 136
         slidingOverlaysQueue.destroy();
128 137
     }
129 138
 
@@ -220,6 +229,27 @@ public class SingleScreenLayout extends BaseLayout {
220 229
         snackbarAndFabContainer.dismissSnackbar();
221 230
     }
222 231
 
232
+    @Override
233
+    public void showLightBox(LightBoxParams params) {
234
+        if (lightBox == null) {
235
+            lightBox = new LightBox(getActivity(), new Runnable() {
236
+                @Override
237
+                public void run() {
238
+                    lightBox = null;
239
+                }
240
+            }, params);
241
+            lightBox.show();
242
+        }
243
+    }
244
+
245
+    @Override
246
+    public void dismissLightBox() {
247
+        if (lightBox != null) {
248
+            lightBox.hide();
249
+            lightBox = null;
250
+        }
251
+    }
252
+
223 253
     @Override
224 254
     public void showSlidingOverlay(final SlidingOverlayParams params) {
225 255
         slidingOverlaysQueue.add(new SlidingOverlay(this, params));

+ 7
- 0
android/app/src/main/java/com/reactnativenavigation/params/LightBoxParams.java Ver arquivo

@@ -0,0 +1,7 @@
1
+package com.reactnativenavigation.params;
2
+
3
+public class LightBoxParams {
4
+    public String screenId;
5
+    public NavigationParams navigationParams;
6
+    public StyleParams.Color backgroundColor;
7
+}

+ 25
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/LightBoxParamsParser.java Ver arquivo

@@ -0,0 +1,25 @@
1
+package com.reactnativenavigation.params.parsers;
2
+
3
+import android.os.Bundle;
4
+
5
+import com.reactnativenavigation.params.LightBoxParams;
6
+import com.reactnativenavigation.params.NavigationParams;
7
+
8
+public class LightBoxParamsParser extends Parser {
9
+    private Bundle params;
10
+
11
+    public LightBoxParamsParser(Bundle params) {
12
+        this.params = params;
13
+    }
14
+
15
+    public LightBoxParams parse() {
16
+        LightBoxParams result = new LightBoxParams();
17
+        if (params.isEmpty()) {
18
+            return result;
19
+        }
20
+        result.screenId = params.getString("screenId");
21
+        result.navigationParams = new NavigationParams(params.getBundle("navigationParams"));
22
+        result.backgroundColor = getColor(params, "backgroundColor");
23
+        return result;
24
+    }
25
+}

+ 126
- 0
android/app/src/main/java/com/reactnativenavigation/views/LightBox.java Ver arquivo

@@ -0,0 +1,126 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.animation.Animator;
4
+import android.animation.AnimatorListenerAdapter;
5
+import android.animation.AnimatorSet;
6
+import android.animation.ObjectAnimator;
7
+import android.app.Dialog;
8
+import android.content.Context;
9
+import android.content.DialogInterface;
10
+import android.graphics.Color;
11
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
12
+import android.support.v7.app.AppCompatActivity;
13
+import android.view.View;
14
+import android.view.ViewGroup;
15
+import android.view.Window;
16
+import android.widget.RelativeLayout;
17
+
18
+import com.reactnativenavigation.R;
19
+import com.reactnativenavigation.params.LightBoxParams;
20
+import com.reactnativenavigation.screens.Screen;
21
+import com.reactnativenavigation.utils.ViewUtils;
22
+
23
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
24
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
25
+
26
+public class LightBox extends Dialog implements DialogInterface.OnDismissListener {
27
+
28
+    private Runnable onDismissListener;
29
+    private ContentView content;
30
+    private RelativeLayout lightBox;
31
+
32
+    public LightBox(AppCompatActivity activity, Runnable onDismissListener, LightBoxParams params) {
33
+        super(activity, R.style.LightBox);
34
+        this.onDismissListener = onDismissListener;
35
+        setOnDismissListener(this);
36
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
37
+        createContent(activity, params);
38
+        getWindow().setWindowAnimations(android.R.style.Animation);
39
+    }
40
+
41
+    private void createContent(final Context context, LightBoxParams params) {
42
+        lightBox = new RelativeLayout(context);
43
+        lightBox.setAlpha(0);
44
+        content = new ContentView(context, params.screenId, params.navigationParams);
45
+        content.setAlpha(0);
46
+        content.setId(ViewUtils.generateViewId());
47
+        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
48
+        lp.addRule(RelativeLayout.CENTER_IN_PARENT, content.getId());
49
+        lightBox.setBackgroundColor(params.backgroundColor.getColor());
50
+        lightBox.addView(content, lp);
51
+
52
+        content.setOnDisplayListener(new Screen.OnDisplayListener() {
53
+            @Override
54
+            public void onDisplay() {
55
+                content.getLayoutParams().height = content.getChildAt(0).getHeight();
56
+                content.getLayoutParams().width = content.getChildAt(0).getWidth();
57
+                content.setBackgroundColor(Color.TRANSPARENT);
58
+                ViewUtils.runOnPreDraw(content, new Runnable() {
59
+                    @Override
60
+                    public void run() {
61
+                        animateShow();
62
+
63
+                    }
64
+                });
65
+            }
66
+        });
67
+        setContentView(lightBox, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
68
+    }
69
+
70
+    @Override
71
+    public void show() {
72
+        super.show();
73
+    }
74
+
75
+    @Override
76
+    public void hide() {
77
+        animateHide();
78
+    }
79
+
80
+    @Override
81
+    public void onDismiss(DialogInterface dialogInterface) {
82
+        onDismissListener.run();
83
+    }
84
+
85
+    public void destroy() {
86
+        content.unmountReactView();
87
+        dismiss();
88
+    }
89
+
90
+    private void animateShow() {
91
+        ObjectAnimator yTranslation = ObjectAnimator.ofFloat(content, View.TRANSLATION_Y, 80, 0).setDuration(400);
92
+        yTranslation.setInterpolator(new FastOutSlowInInterpolator());
93
+        yTranslation.addListener(new AnimatorListenerAdapter() {
94
+            @Override
95
+            public void onAnimationStart(Animator animation) {
96
+                content.setAlpha(1);
97
+            }
98
+        });
99
+
100
+        ObjectAnimator lightBoxAlpha = ObjectAnimator.ofFloat(lightBox, View.ALPHA, 0, 1).setDuration(70);
101
+
102
+        AnimatorSet animatorSet = new AnimatorSet();
103
+        animatorSet.playTogether(lightBoxAlpha, yTranslation);
104
+        animatorSet.start();
105
+    }
106
+
107
+    private void animateHide() {
108
+        ObjectAnimator alpha = ObjectAnimator.ofFloat(content, View.ALPHA, 0);
109
+        ObjectAnimator yTranslation = ObjectAnimator.ofFloat(content, View.TRANSLATION_Y, 60);
110
+        AnimatorSet contentAnimators = new AnimatorSet();
111
+        contentAnimators.playTogether(alpha, yTranslation);
112
+        contentAnimators.setDuration(150);
113
+
114
+        ObjectAnimator lightBoxAlpha = ObjectAnimator.ofFloat(lightBox, View.ALPHA, 0).setDuration(100);
115
+
116
+        AnimatorSet allAnimators = new AnimatorSet();
117
+        allAnimators.playSequentially(contentAnimators, lightBoxAlpha);
118
+        allAnimators.addListener(new AnimatorListenerAdapter() {
119
+            @Override
120
+            public void onAnimationEnd(Animator animation) {
121
+                dismiss();
122
+            }
123
+        });
124
+        allAnimators.start();
125
+    }
126
+}

+ 3
- 0
android/app/src/main/res/anim/lightbox_enter.xml Ver arquivo

@@ -0,0 +1,3 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
3
+           android:duration="@android:integer/config_shortAnimTime"/>

+ 4
- 0
android/app/src/main/res/values/styles.xml Ver arquivo

@@ -4,6 +4,10 @@
4 4
         <item name="android:windowAnimationStyle">@style/modalAnimations</item>
5 5
     </style>
6 6
 
7
+    <style name="LightBox" parent="@android:style/Theme.Translucent.NoTitleBar">
8
+        <item name="android:windowAnimationStyle">@style/modalAnimations</item>
9
+    </style>
10
+
7 11
     <style name="modalAnimations">
8 12
         <item name="android:windowExitAnimation">@anim/slide_down</item>
9 13
     </style>

+ 4
- 0
src/Screen.js Ver arquivo

@@ -44,6 +44,10 @@ class Navigator {
44 44
     return Navigation.showModal(params);
45 45
   }
46 46
 
47
+  showLightBox(params = {}) {
48
+    return Navigation.showLightBox(params);
49
+  }
50
+
47 51
   dismissModal(params = {}) {
48 52
     return Navigation.dismissModal(params);
49 53
   }

+ 24
- 0
src/deprecated/platformSpecificDeprecated.android.js Ver arquivo

@@ -394,6 +394,28 @@ function showModal(params) {
394 394
   newPlatformSpecific.showModal(adapted);
395 395
 }
396 396
 
397
+function showLightBox(params) {
398
+  params.navigationParams = {};
399
+  addNavigatorParams(params.navigationParams);
400
+  params.screenId = params.screen;
401
+  const backgroundBlur = _.get(params, 'style.backgroundBlur');
402
+  const backgroundColor = _.get(params, 'style.backgroundColor');
403
+  if (backgroundColor) {
404
+    params.backgroundColor = processColor(params.backgroundColor);
405
+  } else {
406
+    if (backgroundBlur === 'dark') {
407
+      params.backgroundColor = processColor('rgba(0, 0, 0, 0.5)');
408
+    } else {
409
+      params.backgroundColor = processColor('transparent');
410
+    }
411
+  }
412
+  newPlatformSpecific.showLightBox(params);
413
+}
414
+
415
+function dismissLightBox() {
416
+  newPlatformSpecific.dismissLightBox();
417
+}
418
+
397 419
 function dismissModal() {
398 420
   newPlatformSpecific.dismissTopModal();
399 421
 }
@@ -625,6 +647,8 @@ export default {
625 647
   dismissModal,
626 648
   dismissAllModals,
627 649
   showInAppNotification,
650
+  showLightBox,
651
+  dismissLightBox,
628 652
   dismissInAppNotification,
629 653
   navigatorSetButtons,
630 654
   navigatorSetTabBadge,

+ 11
- 0
src/platformSpecific.android.js Ver arquivo

@@ -53,6 +53,15 @@ function showModal(screenParams) {
53 53
   NativeReactModule.showModal(screenParams);
54 54
 }
55 55
 
56
+function showLightBox(params) {
57
+  savePassProps(params);
58
+  NativeReactModule.showLightBox(params);
59
+}
60
+
61
+function dismissLightBox() {
62
+  NativeReactModule.dismissLightBox();
63
+}
64
+
56 65
 function dismissTopModal() {
57 66
   NativeReactModule.dismissTopModal();
58 67
 }
@@ -158,6 +167,8 @@ module.exports = {
158 167
   showModal,
159 168
   dismissTopModal,
160 169
   dismissAllModals,
170
+  showLightBox,
171
+  dismissLightBox,
161 172
   showInAppNotification,
162 173
   dismissInAppNotification,
163 174
   toggleSideMenuVisible,