Browse Source

fix bug with FAB and toggleBottomTabs

Daniel Zlotin 7 years ago
parent
commit
34052a901d

+ 485
- 478
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java View File

@@ -8,6 +8,7 @@ import android.support.v4.widget.DrawerLayout;
8 8
 import android.support.v7.app.AppCompatActivity;
9 9
 import android.view.View;
10 10
 import android.widget.RelativeLayout;
11
+
11 12
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
12 13
 import com.facebook.react.bridge.Arguments;
13 14
 import com.facebook.react.bridge.Callback;
@@ -45,482 +46,488 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
45 46
 @SuppressLint("ViewConstructor")
46 47
 public class BottomTabsLayout extends BaseLayout implements AHBottomNavigation.OnTabSelectedListener {
47 48
 
48
-    private ActivityParams params;
49
-    private SnackbarAndFabContainer snackbarAndFabContainer;
50
-    private BottomTabs bottomTabs;
51
-    private ScreenStack[] screenStacks;
52
-    private final SideMenuParams leftSideMenuParams;
53
-    private final SideMenuParams rightSideMenuParams;
54
-    private final SlidingOverlaysQueue slidingOverlaysQueue = new SlidingOverlaysQueue();
55
-    private @Nullable SideMenu sideMenu;
56
-    private int currentStackIndex = 0;
57
-    private LightBox lightBox;
58
-
59
-    public BottomTabsLayout(AppCompatActivity activity, ActivityParams params) {
60
-        super(activity);
61
-        this.params = params;
62
-        leftSideMenuParams = params.leftSideMenuParams;
63
-        rightSideMenuParams = params.rightSideMenuParams;
64
-        screenStacks = new ScreenStack[params.tabParams.size()];
65
-        createLayout();
66
-    }
67
-
68
-    private void createLayout() {
69
-        createSideMenu();
70
-        createBottomTabs();
71
-        addBottomTabs();
72
-        addScreenStacks();
73
-        createSnackbarContainer();
74
-        showInitialScreenStack();
75
-    }
76
-
77
-    private void createSideMenu() {
78
-        if (leftSideMenuParams == null && rightSideMenuParams == null) {
79
-            return;
80
-        }
81
-        sideMenu = new SideMenu(getContext(), leftSideMenuParams, rightSideMenuParams);
82
-        RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
83
-        addView(sideMenu, lp);
84
-    }
85
-
86
-    private void addScreenStacks() {
87
-        for (int i = screenStacks.length - 1; i >= 0; i--) {
88
-            createAndAddScreens(i);
89
-        }
90
-    }
91
-
92
-    private void createAndAddScreens(int position) {
93
-        ScreenParams screenParams = params.tabParams.get(position);
94
-        ScreenStack newStack = new ScreenStack(getActivity(), getScreenStackParent(), screenParams.getNavigatorId(), this);
95
-        newStack.pushInitialScreen(screenParams, createScreenLayoutParams(screenParams));
96
-        screenStacks[position] = newStack;
97
-    }
98
-
99
-    private RelativeLayout getScreenStackParent() {
100
-        return sideMenu == null ? this : sideMenu.getContentContainer();
101
-    }
102
-
103
-    @NonNull
104
-    private LayoutParams createScreenLayoutParams(ScreenParams params) {
105
-        LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
106
-        if (params.styleParams.drawScreenAboveBottomTabs) {
107
-            lp.addRule(RelativeLayout.ABOVE, bottomTabs.getId());
108
-        }
109
-        return lp;
110
-    }
111
-
112
-    private void createBottomTabs() {
113
-        bottomTabs = new BottomTabs(getContext());
114
-        bottomTabs.addTabs(params.tabParams, this);
115
-    }
116
-
117
-    private void addBottomTabs() {
118
-        LayoutParams lp = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
119
-        lp.addRule(ALIGN_PARENT_BOTTOM);
120
-        getScreenStackParent().addView(bottomTabs, lp);
121
-    }
122
-
123
-    private void createSnackbarContainer() {
124
-        snackbarAndFabContainer = new SnackbarAndFabContainer(getContext(), this);
125
-        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
126
-        alignSnackbarContainerWithBottomTabs(lp, getCurrentScreen().getStyleParams());
127
-        snackbarAndFabContainer.setClickable(false);
128
-        getScreenStackParent().addView(snackbarAndFabContainer, lp);
129
-    }
130
-
131
-    private void showInitialScreenStack() {
132
-        showStackAndUpdateStyle(screenStacks[0]);
133
-        EventBus.instance.post(new ScreenChangedEvent(screenStacks[0].peek().getScreenParams()));
134
-    }
135
-
136
-    @Override
137
-    public View asView() {
138
-        return this;
139
-    }
140
-
141
-    @Override
142
-    public boolean onBackPressed() {
143
-        if (getCurrentScreenStack().handleBackPressInJs()) {
144
-            return true;
145
-        }
146
-
147
-        if (getCurrentScreenStack().canPop()) {
148
-            getCurrentScreenStack().pop(true);
149
-            setBottomTabsStyleFromCurrentScreen();
150
-            EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
151
-            return true;
152
-        } else {
153
-            return false;
154
-        }
155
-    }
156
-
157
-    @Override
158
-    public void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) {
159
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
160
-            screenStacks[i].setScreenTopBarVisible(screenInstanceId, hidden, animated);
161
-        }
162
-    }
163
-
164
-    public void setBottomTabsVisible(boolean hidden, boolean animated) {
165
-        bottomTabs.setVisibility(hidden, animated);
166
-    }
167
-
168
-    @Override
169
-    public void setTitleBarTitle(String screenInstanceId, String title) {
170
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
171
-            screenStacks[i].setScreenTitleBarTitle(screenInstanceId, title);
172
-        }
173
-    }
174
-
175
-    @Override
176
-    public void setTitleBarSubtitle(String screenInstanceId, String subtitle) {
177
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
178
-            screenStacks[i].setScreenTitleBarSubtitle(screenInstanceId, subtitle);
179
-        }
180
-    }
181
-
182
-    @Override
183
-    public void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, List<TitleBarButtonParams> titleBarButtons) {
184
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
185
-            screenStacks[i].setScreenTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarButtons);
186
-        }
187
-    }
188
-
189
-    @Override
190
-    public void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButtonParams) {
191
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
192
-            screenStacks[i].setScreenTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButtonParams);
193
-        }
194
-    }
195
-
196
-    @Override
197
-    public void setFab(String screenInstanceId, String navigatorEventId, FabParams fabParams) {
198
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
199
-            screenStacks[i].setFab(screenInstanceId, fabParams);
200
-        }
201
-    }
202
-
203
-    @Override
204
-    public void updateScreenStyle(String screenInstanceId, Bundle styleParams) {
205
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
206
-            screenStacks[i].updateScreenStyle(screenInstanceId, styleParams);
207
-        }
208
-    }
209
-
210
-    @Override
211
-    public void selectTopTabByTabIndex(String screenInstanceId, int index) {
212
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
213
-            screenStacks[i].selectTopTabByTabIndex(screenInstanceId, index);
214
-        }
215
-    }
216
-
217
-    @Override
218
-    public void selectTopTabByScreen(String screenInstanceId) {
219
-        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
220
-            screenStacks[i].selectTopTabByScreen(screenInstanceId);
221
-        }
222
-    }
223
-
224
-    @Override
225
-    public void toggleSideMenuVisible(boolean animated, Side side) {
226
-        if (sideMenu != null) {
227
-            sideMenu.toggleVisible(animated, side);
228
-        }
229
-    }
230
-
231
-    @Override
232
-    public void setSideMenuVisible(boolean animated, boolean visible, Side side) {
233
-        if (sideMenu != null) {
234
-            sideMenu.setVisible(visible, animated, side);
235
-        }
236
-    }
237
-
238
-    @Override
239
-    public void setSideMenuEnabled(boolean enabled, Side side) {
240
-        if (sideMenu != null) {
241
-            sideMenu.setDrawerLockMode(enabled ? DrawerLayout.LOCK_MODE_UNLOCKED : DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
242
-        }
243
-    }
244
-
245
-    @Override
246
-    public void showSnackbar(SnackbarParams params) {
247
-        final String eventId = getCurrentScreenStack().peek().getNavigatorEventId();
248
-        snackbarAndFabContainer.showSnackbar(eventId, params);
249
-    }
250
-
251
-    @Override
252
-    public void dismissSnackbar() {
253
-        snackbarAndFabContainer.dismissSnackbar();
254
-    }
255
-
256
-    @Override
257
-    public void showLightBox(LightBoxParams params) {
258
-        if (lightBox == null) {
259
-            lightBox = new LightBox(getActivity(), new Runnable() {
260
-                @Override
261
-                public void run() {
262
-                    lightBox = null;
263
-                }
264
-            }, params);
265
-            lightBox.show();
266
-        }
267
-    }
268
-
269
-    @Override
270
-    public void dismissLightBox() {
271
-        if (lightBox != null) {
272
-            lightBox.hide();
273
-            lightBox = null;
274
-        }
275
-    }
276
-
277
-    @Override
278
-    public void showSlidingOverlay(final SlidingOverlayParams params) {
279
-        slidingOverlaysQueue.add(new SlidingOverlay(this, params));
280
-    }
281
-
282
-    @Override
283
-    public void hideSlidingOverlay() {
284
-        slidingOverlaysQueue.remove();
285
-    }
286
-
287
-    @Override
288
-    public void onModalDismissed() {
289
-        EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
290
-    }
291
-
292
-    @Override
293
-    public boolean containsNavigator(String navigatorId) {
294
-        // Unused
295
-        return false;
296
-    }
297
-
298
-    @Override
299
-    public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) {
300
-        getCurrentScreenStack().peek().showContextualMenu(params, onButtonClicked);
301
-    }
302
-
303
-    @Override
304
-    public void dismissContextualMenu(String screenInstanceId) {
305
-        getCurrentScreenStack().peek().dismissContextualMenu();
306
-    }
307
-
308
-    @Override
309
-    public Screen getCurrentScreen() {
310
-        return getCurrentScreenStack().peek();
311
-    }
312
-
313
-    public void selectBottomTabByTabIndex(Integer index) {
314
-        bottomTabs.setCurrentItem(index);
315
-    }
316
-
317
-    public void selectBottomTabByNavigatorId(String navigatorId) {
318
-        bottomTabs.setCurrentItem(getScreenStackIndex(navigatorId));
319
-    }
320
-
321
-    private boolean hasBackgroundColor(StyleParams params) {
322
-        return params.screenBackgroundColor != null &&
323
-                params.screenBackgroundColor.hasColor();
324
-    }
325
-
326
-    private void setStyleFromScreen(StyleParams params) {
327
-        bottomTabs.setStyleFromScreen(params);
328
-        if (hasBackgroundColor(params)) {
329
-            asView().setBackgroundColor(params.screenBackgroundColor.getColor());
330
-        }
331
-    }
332
-
333
-    @Override
334
-    public void push(ScreenParams params) {
335
-        ScreenStack screenStack = getScreenStack(params.getNavigatorId());
336
-        screenStack.push(params, createScreenLayoutParams(params));
337
-        setStyleFromScreen(params.styleParams);
338
-        if (isCurrentStack(screenStack)) {
339
-            alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
340
-            EventBus.instance.post(new ScreenChangedEvent(params));
341
-        }
342
-    }
343
-
344
-    @Override
345
-    public void pop(final ScreenParams params) {
346
-        getCurrentScreenStack().pop(params.animateScreenTransitions, new ScreenStack.OnScreenPop() {
347
-            @Override
348
-            public void onScreenPopAnimationEnd() {
349
-                setBottomTabsStyleFromCurrentScreen();
350
-                alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
351
-                EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
352
-            }
353
-        });
354
-    }
355
-
356
-    @Override
357
-    public void popToRoot(final ScreenParams params) {
358
-        getCurrentScreenStack().popToRoot(params.animateScreenTransitions, new ScreenStack.OnScreenPop() {
359
-            @Override
360
-            public void onScreenPopAnimationEnd() {
361
-                setBottomTabsStyleFromCurrentScreen();
362
-                alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
363
-                EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
364
-            }
365
-        });
366
-    }
367
-
368
-    @Override
369
-    public void newStack(final ScreenParams params) {
370
-        ScreenStack screenStack = getScreenStack(params.getNavigatorId());
371
-        screenStack.newStack(params, createScreenLayoutParams(params));
372
-        if (isCurrentStack(screenStack)) {
373
-            setStyleFromScreen(params.styleParams);
374
-            alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
375
-            EventBus.instance.post(new ScreenChangedEvent(params));
376
-        }
377
-    }
378
-
379
-    private void alignSnackbarContainerWithBottomTabs(LayoutParams lp, StyleParams styleParams) {
380
-        if (styleParams.drawScreenAboveBottomTabs || !styleParams.bottomTabsHidden) {
381
-            lp.addRule(ABOVE, bottomTabs.getId());
382
-        } else {
383
-            ViewUtils.removeRuleCompat(lp, ABOVE);
384
-        }
385
-    }
386
-
387
-    @Override
388
-    public void destroy() {
389
-        snackbarAndFabContainer.destroy();
390
-        for (ScreenStack screenStack : screenStacks) {
391
-            screenStack.destroy();
392
-        }
393
-        if (sideMenu != null) {
394
-            sideMenu.destroy();
395
-        }
396
-        if (lightBox != null) {
397
-            lightBox.destroy();
398
-            lightBox = null;
399
-        }
400
-        slidingOverlaysQueue.destroy();
401
-    }
402
-
403
-    @Override
404
-    public boolean onTabSelected(int position, boolean wasSelected) {
405
-        if (wasSelected) {
406
-            sendTabReselectedEventToJs();
407
-            return false;
408
-        }
409
-
410
-        final int unselectedTabIndex = currentStackIndex;
411
-        hideCurrentStack();
412
-        showNewStack(position);
413
-        EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
414
-        sendTabSelectedEventToJs(position, unselectedTabIndex);
415
-        return true;
416
-    }
417
-
418
-    private void sendTabSelectedEventToJs(int selectedTabIndex, int unselectedTabIndex) {
419
-        String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
420
-        WritableMap data = createTabSelectedEventData(selectedTabIndex, unselectedTabIndex);
421
-        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabSelected", navigatorEventId, data);
422
-
423
-        data = createTabSelectedEventData(selectedTabIndex, unselectedTabIndex);
424
-        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabSelected", data);
425
-    }
426
-
427
-    private WritableMap createTabSelectedEventData(int selectedTabIndex, int unselectedTabIndex) {
428
-        WritableMap data = Arguments.createMap();
429
-        data.putInt("selectedTabIndex", selectedTabIndex);
430
-        data.putInt("unselectedTabIndex", unselectedTabIndex);
431
-        return data;
432
-    }
433
-
434
-    private void sendTabReselectedEventToJs() {
435
-        WritableMap data = Arguments.createMap();
436
-        String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
437
-        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabReselected", navigatorEventId, data);
438
-    }
439
-
440
-    private void showNewStack(int position) {
441
-        showStackAndUpdateStyle(screenStacks[position]);
442
-        currentStackIndex = position;
443
-    }
444
-
445
-    private void showStackAndUpdateStyle(ScreenStack newStack) {
446
-        newStack.show();
447
-        setStyleFromScreen(newStack.getCurrentScreenStyleParams());
448
-    }
449
-
450
-    private void hideCurrentStack() {
451
-        ScreenStack currentScreenStack = getCurrentScreenStack();
452
-        currentScreenStack.hide();
453
-    }
454
-
455
-    private ScreenStack getCurrentScreenStack() {
456
-        return screenStacks[currentStackIndex];
457
-    }
458
-
459
-    private @NonNull ScreenStack getScreenStack(String navigatorId) {
460
-        int index = getScreenStackIndex(navigatorId);
461
-        return screenStacks[index];
462
-    }
463
-
464
-    public void setBottomTabBadgeByIndex(Integer index, String badge) {
465
-        bottomTabs.setNotification(badge, index);
466
-    }
467
-
468
-    public void setBottomTabBadgeByNavigatorId(String navigatorId, String badge) {
469
-        bottomTabs.setNotification(badge, getScreenStackIndex(navigatorId));
470
-    }
471
-
472
-    public void setBottomTabButtonByIndex(Integer index, ScreenParams params) {
473
-        bottomTabs.setTabButton(params, index);
474
-    }
475
-
476
-    public void setBottomTabButtonByNavigatorId(String navigatorId, ScreenParams params) {
477
-        bottomTabs.setTabButton(params, getScreenStackIndex(navigatorId));
478
-    }
479
-
480
-    private int getScreenStackIndex(String navigatorId) throws ScreenStackNotFoundException {
481
-        for (int i = 0; i < screenStacks.length; i++) {
482
-            if (screenStacks[i].getNavigatorId().equals(navigatorId)) {
483
-                return i;
484
-            }
485
-        }
486
-        throw new ScreenStackNotFoundException("Stack " + navigatorId + " not found");
487
-    }
488
-
489
-    private class ScreenStackNotFoundException extends RuntimeException {
490
-        ScreenStackNotFoundException(String navigatorId) {
491
-            super(navigatorId);
492
-        }
493
-    }
494
-
495
-    private boolean isCurrentStack(ScreenStack screenStack) {
496
-        return getCurrentScreenStack() == screenStack;
497
-    }
498
-
499
-    private void setBottomTabsStyleFromCurrentScreen() {
500
-        setStyleFromScreen(getCurrentScreenStack().getCurrentScreenStyleParams());
501
-    }
502
-
503
-    @Override
504
-    public boolean onTitleBarBackButtonClick() {
505
-        if (getCurrentScreenStack().canPop()) {
506
-            getCurrentScreenStack().pop(true, new ScreenStack.OnScreenPop() {
507
-                @Override
508
-                public void onScreenPopAnimationEnd() {
509
-                    setBottomTabsStyleFromCurrentScreen();
510
-                    EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
511
-                }
512
-            });
513
-            return true;
514
-        }
515
-        return false;
516
-    }
517
-
518
-    @Override
519
-    public void onSideMenuButtonClick() {
520
-        final String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
521
-        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("sideMenu", navigatorEventId);
522
-        if (sideMenu != null) {
523
-            sideMenu.openDrawer(Side.Left);
524
-        }
525
-    }
49
+	private ActivityParams params;
50
+	private SnackbarAndFabContainer snackbarAndFabContainer;
51
+	private BottomTabs bottomTabs;
52
+	private ScreenStack[] screenStacks;
53
+	private final SideMenuParams leftSideMenuParams;
54
+	private final SideMenuParams rightSideMenuParams;
55
+	private final SlidingOverlaysQueue slidingOverlaysQueue = new SlidingOverlaysQueue();
56
+	private
57
+	@Nullable
58
+	SideMenu sideMenu;
59
+	private int currentStackIndex = 0;
60
+	private LightBox lightBox;
61
+
62
+	public BottomTabsLayout(AppCompatActivity activity, ActivityParams params) {
63
+		super(activity);
64
+		this.params = params;
65
+		leftSideMenuParams = params.leftSideMenuParams;
66
+		rightSideMenuParams = params.rightSideMenuParams;
67
+		screenStacks = new ScreenStack[params.tabParams.size()];
68
+		createLayout();
69
+	}
70
+
71
+	private void createLayout() {
72
+		createSideMenu();
73
+		createBottomTabs();
74
+		addBottomTabs();
75
+		addScreenStacks();
76
+		createSnackbarContainer();
77
+		showInitialScreenStack();
78
+	}
79
+
80
+	private void createSideMenu() {
81
+		if (leftSideMenuParams == null && rightSideMenuParams == null) {
82
+			return;
83
+		}
84
+		sideMenu = new SideMenu(getContext(), leftSideMenuParams, rightSideMenuParams);
85
+		RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
86
+		addView(sideMenu, lp);
87
+	}
88
+
89
+	private void addScreenStacks() {
90
+		for (int i = screenStacks.length - 1; i >= 0; i--) {
91
+			createAndAddScreens(i);
92
+		}
93
+	}
94
+
95
+	private void createAndAddScreens(int position) {
96
+		ScreenParams screenParams = params.tabParams.get(position);
97
+		ScreenStack newStack = new ScreenStack(getActivity(), getScreenStackParent(), screenParams.getNavigatorId(), this);
98
+		newStack.pushInitialScreen(screenParams, createScreenLayoutParams(screenParams));
99
+		screenStacks[position] = newStack;
100
+	}
101
+
102
+	private RelativeLayout getScreenStackParent() {
103
+		return sideMenu == null ? this : sideMenu.getContentContainer();
104
+	}
105
+
106
+	@NonNull
107
+	private LayoutParams createScreenLayoutParams(ScreenParams params) {
108
+		LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
109
+		if (params.styleParams.drawScreenAboveBottomTabs) {
110
+			lp.addRule(RelativeLayout.ABOVE, bottomTabs.getId());
111
+		}
112
+		return lp;
113
+	}
114
+
115
+	private void createBottomTabs() {
116
+		bottomTabs = new BottomTabs(getContext());
117
+		bottomTabs.addTabs(params.tabParams, this);
118
+	}
119
+
120
+	private void addBottomTabs() {
121
+		LayoutParams lp = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
122
+		lp.addRule(ALIGN_PARENT_BOTTOM);
123
+		getScreenStackParent().addView(bottomTabs, lp);
124
+	}
125
+
126
+	private void createSnackbarContainer() {
127
+		snackbarAndFabContainer = new SnackbarAndFabContainer(getContext(), this);
128
+		RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
129
+		alignSnackbarContainerWithBottomTabs(lp, getCurrentScreen().getStyleParams());
130
+		snackbarAndFabContainer.setClickable(false);
131
+		getScreenStackParent().addView(snackbarAndFabContainer, lp);
132
+	}
133
+
134
+	private void showInitialScreenStack() {
135
+		showStackAndUpdateStyle(screenStacks[0]);
136
+		EventBus.instance.post(new ScreenChangedEvent(screenStacks[0].peek().getScreenParams()));
137
+	}
138
+
139
+	@Override
140
+	public View asView() {
141
+		return this;
142
+	}
143
+
144
+	@Override
145
+	public boolean onBackPressed() {
146
+		if (getCurrentScreenStack().handleBackPressInJs()) {
147
+			return true;
148
+		}
149
+
150
+		if (getCurrentScreenStack().canPop()) {
151
+			getCurrentScreenStack().pop(true);
152
+			setBottomTabsStyleFromCurrentScreen();
153
+			EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
154
+			return true;
155
+		} else {
156
+			return false;
157
+		}
158
+	}
159
+
160
+	@Override
161
+	public void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) {
162
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
163
+			screenStacks[i].setScreenTopBarVisible(screenInstanceId, hidden, animated);
164
+		}
165
+	}
166
+
167
+	public void setBottomTabsVisible(boolean hidden, boolean animated) {
168
+		bottomTabs.setVisibility(hidden, animated);
169
+	}
170
+
171
+	@Override
172
+	public void setTitleBarTitle(String screenInstanceId, String title) {
173
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
174
+			screenStacks[i].setScreenTitleBarTitle(screenInstanceId, title);
175
+		}
176
+	}
177
+
178
+	@Override
179
+	public void setTitleBarSubtitle(String screenInstanceId, String subtitle) {
180
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
181
+			screenStacks[i].setScreenTitleBarSubtitle(screenInstanceId, subtitle);
182
+		}
183
+	}
184
+
185
+	@Override
186
+	public void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, List<TitleBarButtonParams> titleBarButtons) {
187
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
188
+			screenStacks[i].setScreenTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarButtons);
189
+		}
190
+	}
191
+
192
+	@Override
193
+	public void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButtonParams) {
194
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
195
+			screenStacks[i].setScreenTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButtonParams);
196
+		}
197
+	}
198
+
199
+	@Override
200
+	public void setFab(String screenInstanceId, String navigatorEventId, FabParams fabParams) {
201
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
202
+			screenStacks[i].setFab(screenInstanceId, fabParams);
203
+		}
204
+	}
205
+
206
+	@Override
207
+	public void updateScreenStyle(String screenInstanceId, Bundle styleParams) {
208
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
209
+			screenStacks[i].updateScreenStyle(screenInstanceId, styleParams);
210
+		}
211
+	}
212
+
213
+	@Override
214
+	public void selectTopTabByTabIndex(String screenInstanceId, int index) {
215
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
216
+			screenStacks[i].selectTopTabByTabIndex(screenInstanceId, index);
217
+		}
218
+	}
219
+
220
+	@Override
221
+	public void selectTopTabByScreen(String screenInstanceId) {
222
+		for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
223
+			screenStacks[i].selectTopTabByScreen(screenInstanceId);
224
+		}
225
+	}
226
+
227
+	@Override
228
+	public void toggleSideMenuVisible(boolean animated, Side side) {
229
+		if (sideMenu != null) {
230
+			sideMenu.toggleVisible(animated, side);
231
+		}
232
+	}
233
+
234
+	@Override
235
+	public void setSideMenuVisible(boolean animated, boolean visible, Side side) {
236
+		if (sideMenu != null) {
237
+			sideMenu.setVisible(visible, animated, side);
238
+		}
239
+	}
240
+
241
+	@Override
242
+	public void setSideMenuEnabled(boolean enabled, Side side) {
243
+		if (sideMenu != null) {
244
+			sideMenu.setDrawerLockMode(enabled ? DrawerLayout.LOCK_MODE_UNLOCKED : DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
245
+		}
246
+	}
247
+
248
+	@Override
249
+	public void showSnackbar(SnackbarParams params) {
250
+		final String eventId = getCurrentScreenStack().peek().getNavigatorEventId();
251
+		snackbarAndFabContainer.showSnackbar(eventId, params);
252
+	}
253
+
254
+	@Override
255
+	public void dismissSnackbar() {
256
+		snackbarAndFabContainer.dismissSnackbar();
257
+	}
258
+
259
+	@Override
260
+	public void showLightBox(LightBoxParams params) {
261
+		if (lightBox == null) {
262
+			lightBox = new LightBox(getActivity(), new Runnable() {
263
+				@Override
264
+				public void run() {
265
+					lightBox = null;
266
+				}
267
+			}, params);
268
+			lightBox.show();
269
+		}
270
+	}
271
+
272
+	@Override
273
+	public void dismissLightBox() {
274
+		if (lightBox != null) {
275
+			lightBox.hide();
276
+			lightBox = null;
277
+		}
278
+	}
279
+
280
+	@Override
281
+	public void showSlidingOverlay(final SlidingOverlayParams params) {
282
+		slidingOverlaysQueue.add(new SlidingOverlay(this, params));
283
+	}
284
+
285
+	@Override
286
+	public void hideSlidingOverlay() {
287
+		slidingOverlaysQueue.remove();
288
+	}
289
+
290
+	@Override
291
+	public void onModalDismissed() {
292
+		EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
293
+	}
294
+
295
+	@Override
296
+	public boolean containsNavigator(String navigatorId) {
297
+		// Unused
298
+		return false;
299
+	}
300
+
301
+	@Override
302
+	public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) {
303
+		getCurrentScreenStack().peek().showContextualMenu(params, onButtonClicked);
304
+	}
305
+
306
+	@Override
307
+	public void dismissContextualMenu(String screenInstanceId) {
308
+		getCurrentScreenStack().peek().dismissContextualMenu();
309
+	}
310
+
311
+	@Override
312
+	public Screen getCurrentScreen() {
313
+		return getCurrentScreenStack().peek();
314
+	}
315
+
316
+	public void selectBottomTabByTabIndex(Integer index) {
317
+		bottomTabs.setCurrentItem(index);
318
+	}
319
+
320
+	public void selectBottomTabByNavigatorId(String navigatorId) {
321
+		bottomTabs.setCurrentItem(getScreenStackIndex(navigatorId));
322
+	}
323
+
324
+	private boolean hasBackgroundColor(StyleParams params) {
325
+		return params.screenBackgroundColor != null &&
326
+				params.screenBackgroundColor.hasColor();
327
+	}
328
+
329
+	private void setStyleFromScreen(StyleParams params) {
330
+		bottomTabs.setStyleFromScreen(params);
331
+		if (snackbarAndFabContainer != null && snackbarAndFabContainer.getLayoutParams() instanceof RelativeLayout.LayoutParams)
332
+			alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params);
333
+		if (hasBackgroundColor(params)) {
334
+			asView().setBackgroundColor(params.screenBackgroundColor.getColor());
335
+		}
336
+	}
337
+
338
+	@Override
339
+	public void push(ScreenParams params) {
340
+		ScreenStack screenStack = getScreenStack(params.getNavigatorId());
341
+		screenStack.push(params, createScreenLayoutParams(params));
342
+		setStyleFromScreen(params.styleParams);
343
+		if (isCurrentStack(screenStack)) {
344
+			alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
345
+			EventBus.instance.post(new ScreenChangedEvent(params));
346
+		}
347
+	}
348
+
349
+	@Override
350
+	public void pop(final ScreenParams params) {
351
+		getCurrentScreenStack().pop(params.animateScreenTransitions, new ScreenStack.OnScreenPop() {
352
+			@Override
353
+			public void onScreenPopAnimationEnd() {
354
+				setBottomTabsStyleFromCurrentScreen();
355
+				alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
356
+				EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
357
+			}
358
+		});
359
+	}
360
+
361
+	@Override
362
+	public void popToRoot(final ScreenParams params) {
363
+		getCurrentScreenStack().popToRoot(params.animateScreenTransitions, new ScreenStack.OnScreenPop() {
364
+			@Override
365
+			public void onScreenPopAnimationEnd() {
366
+				setBottomTabsStyleFromCurrentScreen();
367
+				alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
368
+				EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
369
+			}
370
+		});
371
+	}
372
+
373
+	@Override
374
+	public void newStack(final ScreenParams params) {
375
+		ScreenStack screenStack = getScreenStack(params.getNavigatorId());
376
+		screenStack.newStack(params, createScreenLayoutParams(params));
377
+		if (isCurrentStack(screenStack)) {
378
+			setStyleFromScreen(params.styleParams);
379
+			alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams);
380
+			EventBus.instance.post(new ScreenChangedEvent(params));
381
+		}
382
+	}
383
+
384
+	private void alignSnackbarContainerWithBottomTabs(LayoutParams lp, StyleParams styleParams) {
385
+		if (styleParams.drawScreenAboveBottomTabs || !styleParams.bottomTabsHidden) {
386
+			lp.addRule(ABOVE, bottomTabs.getId());
387
+		} else {
388
+			ViewUtils.removeRuleCompat(lp, ABOVE);
389
+		}
390
+	}
391
+
392
+	@Override
393
+	public void destroy() {
394
+		snackbarAndFabContainer.destroy();
395
+		for (ScreenStack screenStack : screenStacks) {
396
+			screenStack.destroy();
397
+		}
398
+		if (sideMenu != null) {
399
+			sideMenu.destroy();
400
+		}
401
+		if (lightBox != null) {
402
+			lightBox.destroy();
403
+			lightBox = null;
404
+		}
405
+		slidingOverlaysQueue.destroy();
406
+	}
407
+
408
+	@Override
409
+	public boolean onTabSelected(int position, boolean wasSelected) {
410
+		if (wasSelected) {
411
+			sendTabReselectedEventToJs();
412
+			return false;
413
+		}
414
+
415
+		final int unselectedTabIndex = currentStackIndex;
416
+		hideCurrentStack();
417
+		showNewStack(position);
418
+		EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
419
+		sendTabSelectedEventToJs(position, unselectedTabIndex);
420
+		return true;
421
+	}
422
+
423
+	private void sendTabSelectedEventToJs(int selectedTabIndex, int unselectedTabIndex) {
424
+		String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
425
+		WritableMap data = createTabSelectedEventData(selectedTabIndex, unselectedTabIndex);
426
+		NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabSelected", navigatorEventId, data);
427
+
428
+		data = createTabSelectedEventData(selectedTabIndex, unselectedTabIndex);
429
+		NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabSelected", data);
430
+	}
431
+
432
+	private WritableMap createTabSelectedEventData(int selectedTabIndex, int unselectedTabIndex) {
433
+		WritableMap data = Arguments.createMap();
434
+		data.putInt("selectedTabIndex", selectedTabIndex);
435
+		data.putInt("unselectedTabIndex", unselectedTabIndex);
436
+		return data;
437
+	}
438
+
439
+	private void sendTabReselectedEventToJs() {
440
+		WritableMap data = Arguments.createMap();
441
+		String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
442
+		NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabReselected", navigatorEventId, data);
443
+	}
444
+
445
+	private void showNewStack(int position) {
446
+		showStackAndUpdateStyle(screenStacks[position]);
447
+		currentStackIndex = position;
448
+	}
449
+
450
+	private void showStackAndUpdateStyle(ScreenStack newStack) {
451
+		newStack.show();
452
+		setStyleFromScreen(newStack.getCurrentScreenStyleParams());
453
+	}
454
+
455
+	private void hideCurrentStack() {
456
+		ScreenStack currentScreenStack = getCurrentScreenStack();
457
+		currentScreenStack.hide();
458
+	}
459
+
460
+	private ScreenStack getCurrentScreenStack() {
461
+		return screenStacks[currentStackIndex];
462
+	}
463
+
464
+	private
465
+	@NonNull
466
+	ScreenStack getScreenStack(String navigatorId) {
467
+		int index = getScreenStackIndex(navigatorId);
468
+		return screenStacks[index];
469
+	}
470
+
471
+	public void setBottomTabBadgeByIndex(Integer index, String badge) {
472
+		bottomTabs.setNotification(badge, index);
473
+	}
474
+
475
+	public void setBottomTabBadgeByNavigatorId(String navigatorId, String badge) {
476
+		bottomTabs.setNotification(badge, getScreenStackIndex(navigatorId));
477
+	}
478
+
479
+	public void setBottomTabButtonByIndex(Integer index, ScreenParams params) {
480
+		bottomTabs.setTabButton(params, index);
481
+	}
482
+
483
+	public void setBottomTabButtonByNavigatorId(String navigatorId, ScreenParams params) {
484
+		bottomTabs.setTabButton(params, getScreenStackIndex(navigatorId));
485
+	}
486
+
487
+	private int getScreenStackIndex(String navigatorId) throws ScreenStackNotFoundException {
488
+		for (int i = 0; i < screenStacks.length; i++) {
489
+			if (screenStacks[i].getNavigatorId().equals(navigatorId)) {
490
+				return i;
491
+			}
492
+		}
493
+		throw new ScreenStackNotFoundException("Stack " + navigatorId + " not found");
494
+	}
495
+
496
+	private class ScreenStackNotFoundException extends RuntimeException {
497
+		ScreenStackNotFoundException(String navigatorId) {
498
+			super(navigatorId);
499
+		}
500
+	}
501
+
502
+	private boolean isCurrentStack(ScreenStack screenStack) {
503
+		return getCurrentScreenStack() == screenStack;
504
+	}
505
+
506
+	private void setBottomTabsStyleFromCurrentScreen() {
507
+		setStyleFromScreen(getCurrentScreenStack().getCurrentScreenStyleParams());
508
+	}
509
+
510
+	@Override
511
+	public boolean onTitleBarBackButtonClick() {
512
+		if (getCurrentScreenStack().canPop()) {
513
+			getCurrentScreenStack().pop(true, new ScreenStack.OnScreenPop() {
514
+				@Override
515
+				public void onScreenPopAnimationEnd() {
516
+					setBottomTabsStyleFromCurrentScreen();
517
+					EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams()));
518
+				}
519
+			});
520
+			return true;
521
+		}
522
+		return false;
523
+	}
524
+
525
+	@Override
526
+	public void onSideMenuButtonClick() {
527
+		final String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
528
+		NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("sideMenu", navigatorEventId);
529
+		if (sideMenu != null) {
530
+			sideMenu.openDrawer(Side.Left);
531
+		}
532
+	}
526 533
 }

+ 1
- 1
example/package.json View File

@@ -14,7 +14,7 @@
14 14
     "react": "16.0.0-alpha.12",
15 15
     "react-native": "0.45.1",
16 16
     "react-native-animatable": "^1.1.0",
17
-    "react-native-navigation": "latest"
17
+    "react-native-navigation": "../"
18 18
   },
19 19
   "devDependencies": {
20 20
     "detox": "^5.0.0",

+ 11
- 10
example/src/screens/Actions.js View File

@@ -1,5 +1,5 @@
1 1
 import React from 'react';
2
-import {StyleSheet, ScrollView} from 'react-native';
2
+import { StyleSheet, ScrollView } from 'react-native';
3 3
 import Row from '../components/Row';
4 4
 
5 5
 class Actions extends React.Component {
@@ -141,15 +141,16 @@ class Actions extends React.Component {
141 141
   render() {
142 142
     return (
143 143
       <ScrollView style={styles.container}>
144
-        <Row title={'Set Title'} onPress={this.setTitle}/>
145
-        <Row title={'Toggle Tabs'} onPress={this.toggleTabs}/>
146
-        <Row title={'Set Tab Badge'} onPress={this.setTabBadge}/>
147
-        <Row title={'Switch To Tab 0'} onPress={this.switchToTab}/>
148
-        <Row title={'Toggle Nav Bar'} onPress={this.toggleNavBar}/>
149
-        <Row title={'Show Snackbar'} onPress={this.showSnackbar} platform={'android'}/>
150
-        <Row title={'Toggle Contextual Menu'} onPress={this.toggleContextualMenu} platform={'android'}/>
151
-        <Row title={'Set Right Buttons'} onPress={this.setButtons}/>
152
-        <Row title={'Toggle FAB'} onPress={this.toggleFAB} platform={'android'}/>
144
+        <Row title={'Push'} onPress={() => this.props.navigator.push({ screen: 'example.Types.Push', title: 'New Screen', navigatorStyle: { tabBarHidden: true } })} />
145
+        <Row title={'Set Title'} onPress={this.setTitle} />
146
+        <Row title={'Toggle Tabs'} onPress={this.toggleTabs} />
147
+        <Row title={'Set Tab Badge'} onPress={this.setTabBadge} />
148
+        <Row title={'Switch To Tab 0'} onPress={this.switchToTab} />
149
+        <Row title={'Toggle Nav Bar'} onPress={this.toggleNavBar} />
150
+        <Row title={'Show Snackbar'} onPress={this.showSnackbar} platform={'android'} />
151
+        <Row title={'Toggle Contextual Menu'} onPress={this.toggleContextualMenu} platform={'android'} />
152
+        <Row title={'Set Right Buttons'} onPress={this.setButtons} />
153
+        <Row title={'Toggle FAB'} onPress={this.toggleFAB} platform={'android'} />
153 154
       </ScrollView>
154 155
     );
155 156
   }