瀏覽代碼

Add support for ContextualMenu in TopBar

Guy Carmeli 8 年之前
父節點
當前提交
3c31e158da
共有 31 個檔案被更改,包括 453 行新增49 行删除
  1. 10
    0
      android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java
  2. 6
    0
      android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java
  3. 16
    0
      android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java
  4. 9
    0
      android/app/src/main/java/com/reactnativenavigation/events/ContextualMenuHiddenEvent.java
  5. 10
    0
      android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenChangedEvent.java
  6. 7
    0
      android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java
  7. 4
    0
      android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java
  8. 7
    0
      android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java
  9. 33
    0
      android/app/src/main/java/com/reactnativenavigation/params/BaseTitleBarButtonParams.java
  10. 5
    0
      android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuButtonParams.java
  11. 16
    0
      android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuParams.java
  12. 3
    0
      android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java
  13. 1
    20
      android/app/src/main/java/com/reactnativenavigation/params/TitleBarButtonParams.java
  14. 30
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuButtonParamsParser.java
  15. 16
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuParamsParser.java
  16. 2
    2
      android/app/src/main/java/com/reactnativenavigation/params/parsers/ScreenParamsParser.java
  17. 15
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/StyleParamsParser.java
  18. 7
    6
      android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java
  19. 4
    2
      android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java
  20. 5
    0
      android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java
  21. 33
    4
      android/app/src/main/java/com/reactnativenavigation/screens/Screen.java
  22. 1
    1
      android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java
  23. 5
    0
      android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java
  24. 74
    0
      android/app/src/main/java/com/reactnativenavigation/views/ContextualMenu.java
  25. 28
    0
      android/app/src/main/java/com/reactnativenavigation/views/ContextualMenuButton.java
  26. 27
    3
      android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java
  27. 6
    5
      android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java
  28. 40
    2
      android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  29. 4
    0
      src/Screen.js
  30. 23
    3
      src/deprecated/platformSpecificDeprecated.android.js
  31. 6
    1
      src/platformSpecific.android.js

+ 10
- 0
android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java 查看文件

@@ -1,14 +1,17 @@
1 1
 package com.reactnativenavigation.bridge;
2 2
 
3
+import com.facebook.react.bridge.Callback;
3 4
 import com.facebook.react.bridge.ReactApplicationContext;
4 5
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
5 6
 import com.facebook.react.bridge.ReactMethod;
6 7
 import com.facebook.react.bridge.ReadableArray;
7 8
 import com.facebook.react.bridge.ReadableMap;
8 9
 import com.reactnativenavigation.controllers.NavigationCommandsHandler;
10
+import com.reactnativenavigation.params.ContextualMenuParams;
9 11
 import com.reactnativenavigation.params.SnackbarParams;
10 12
 import com.reactnativenavigation.params.TitleBarButtonParams;
11 13
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
14
+import com.reactnativenavigation.params.parsers.ContextualMenuParamsParser;
12 15
 import com.reactnativenavigation.params.parsers.SnackbarParamsParser;
13 16
 import com.reactnativenavigation.params.parsers.TitleBarButtonParamsParser;
14 17
 import com.reactnativenavigation.params.parsers.TitleBarLeftButtonParamsParser;
@@ -170,4 +173,11 @@ public class NavigationReactModule extends ReactContextBaseJavaModule {
170 173
         SnackbarParams snackbarParams = new SnackbarParamsParser().parse(BundleConverter.toBundle(params));
171 174
         NavigationCommandsHandler.showSnackbar(snackbarParams);
172 175
     }
176
+
177
+    @ReactMethod
178
+    public void showContextualMenu(final ReadableMap params, final Callback onButtonClicked) {
179
+        ContextualMenuParams contextualMenuParams =
180
+                new ContextualMenuParamsParser().parse(BundleConverter.toBundle(params));
181
+        NavigationCommandsHandler.showContextualMenu(contextualMenuParams, onButtonClicked);
182
+    }
173 183
 }

+ 6
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java 查看文件

@@ -5,6 +5,7 @@ import android.os.Bundle;
5 5
 import android.support.v7.app.AppCompatActivity;
6 6
 import android.view.KeyEvent;
7 7
 
8
+import com.facebook.react.bridge.Callback;
8 9
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
9 10
 import com.reactnativenavigation.NavigationApplication;
10 11
 import com.reactnativenavigation.events.Event;
@@ -16,6 +17,7 @@ import com.reactnativenavigation.layouts.BottomTabsLayout;
16 17
 import com.reactnativenavigation.layouts.Layout;
17 18
 import com.reactnativenavigation.layouts.LayoutFactory;
18 19
 import com.reactnativenavigation.params.ActivityParams;
20
+import com.reactnativenavigation.params.ContextualMenuParams;
19 21
 import com.reactnativenavigation.params.ScreenParams;
20 22
 import com.reactnativenavigation.params.SnackbarParams;
21 23
 import com.reactnativenavigation.params.TitleBarButtonParams;
@@ -248,6 +250,10 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard
248 250
         layout.showSnackbar(params);
249 251
     }
250 252
 
253
+    public void showContextualMenu(ContextualMenuParams params, Callback onButtonClicked) {
254
+        layout.showContextualMenu(params, onButtonClicked);
255
+    }
256
+
251 257
     @Override
252 258
     public void onEvent(Event event) {
253 259
         if (event.getType().equals(ModalDismissedEvent.TYPE)) {

+ 16
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java 查看文件

@@ -3,8 +3,10 @@ package com.reactnativenavigation.controllers;
3 3
 import android.content.Intent;
4 4
 import android.os.Bundle;
5 5
 
6
+import com.facebook.react.bridge.Callback;
6 7
 import com.reactnativenavigation.NavigationApplication;
7 8
 import com.reactnativenavigation.params.ActivityParams;
9
+import com.reactnativenavigation.params.ContextualMenuParams;
8 10
 import com.reactnativenavigation.params.ScreenParams;
9 11
 import com.reactnativenavigation.params.SnackbarParams;
10 12
 import com.reactnativenavigation.params.TitleBarButtonParams;
@@ -328,4 +330,18 @@ public class NavigationCommandsHandler {
328 330
             }
329 331
         });
330 332
     }
333
+
334
+    public static void showContextualMenu(final ContextualMenuParams params, final Callback onButtonClicked) {
335
+        final NavigationActivity currentActivity = NavigationActivity.currentActivity;
336
+        if (currentActivity == null) {
337
+            return;
338
+        }
339
+
340
+        NavigationApplication.instance.runOnMainThread(new Runnable() {
341
+            @Override
342
+            public void run() {
343
+                currentActivity.showContextualMenu(params, onButtonClicked);
344
+            }
345
+        });
346
+    }
331 347
 }

+ 9
- 0
android/app/src/main/java/com/reactnativenavigation/events/ContextualMenuHiddenEvent.java 查看文件

@@ -0,0 +1,9 @@
1
+package com.reactnativenavigation.events;
2
+
3
+public class ContextualMenuHiddenEvent implements Event {
4
+    public static final String TYPE = "ContextualMenuDismissed";
5
+    @Override
6
+    public String getType() {
7
+        return TYPE;
8
+    }
9
+}

+ 10
- 0
android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenChangedEvent.java 查看文件

@@ -0,0 +1,10 @@
1
+package com.reactnativenavigation.events;
2
+
3
+public class ViewPagerScreenChangedEvent implements Event {
4
+    public static final String TYPE = "ViewPagerScreenChangedEvent";
5
+
6
+    @Override
7
+    public String getType() {
8
+        return TYPE;
9
+    }
10
+}

+ 7
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java 查看文件

@@ -7,10 +7,12 @@ import android.view.View;
7 7
 import android.widget.RelativeLayout;
8 8
 
9 9
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
10
+import com.facebook.react.bridge.Callback;
10 11
 import com.reactnativenavigation.NavigationApplication;
11 12
 import com.reactnativenavigation.events.EventBus;
12 13
 import com.reactnativenavigation.events.ScreenChangedEvent;
13 14
 import com.reactnativenavigation.params.ActivityParams;
15
+import com.reactnativenavigation.params.ContextualMenuParams;
14 16
 import com.reactnativenavigation.params.ScreenParams;
15 17
 import com.reactnativenavigation.params.SideMenuParams;
16 18
 import com.reactnativenavigation.params.SnackbarParams;
@@ -204,6 +206,11 @@ public class BottomTabsLayout extends RelativeLayout implements Layout, AHBottom
204 206
         return false;
205 207
     }
206 208
 
209
+    @Override
210
+    public void showContextualMenu(ContextualMenuParams params, Callback onButtonClicked) {
211
+        getCurrentScreenStack().peek().showContextualMenu(params, onButtonClicked);
212
+    }
213
+
207 214
     public void selectBottomTabByTabIndex(Integer index) {
208 215
         bottomTabs.setCurrentItem(index);
209 216
     }

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java 查看文件

@@ -2,6 +2,8 @@ package com.reactnativenavigation.layouts;
2 2
 
3 3
 import android.view.View;
4 4
 
5
+import com.facebook.react.bridge.Callback;
6
+import com.reactnativenavigation.params.ContextualMenuParams;
5 7
 import com.reactnativenavigation.params.SnackbarParams;
6 8
 import com.reactnativenavigation.params.TitleBarButtonParams;
7 9
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
@@ -32,4 +34,6 @@ public interface Layout extends ScreenStackContainer {
32 34
     void onModalDismissed();
33 35
 
34 36
     boolean containsNavigator(String navigatorId);
37
+
38
+    void showContextualMenu(ContextualMenuParams params, Callback onButtonClicked);
35 39
 }

+ 7
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java 查看文件

@@ -5,9 +5,11 @@ import android.support.v7.app.AppCompatActivity;
5 5
 import android.view.View;
6 6
 import android.widget.RelativeLayout;
7 7
 
8
+import com.facebook.react.bridge.Callback;
8 9
 import com.reactnativenavigation.NavigationApplication;
9 10
 import com.reactnativenavigation.events.EventBus;
10 11
 import com.reactnativenavigation.events.ScreenChangedEvent;
12
+import com.reactnativenavigation.params.ContextualMenuParams;
11 13
 import com.reactnativenavigation.params.ScreenParams;
12 14
 import com.reactnativenavigation.params.SideMenuParams;
13 15
 import com.reactnativenavigation.params.SnackbarParams;
@@ -209,6 +211,11 @@ public class SingleScreenLayout extends RelativeLayout implements Layout {
209 211
         return stack.getNavigatorId().equals(navigatorId);
210 212
     }
211 213
 
214
+    @Override
215
+    public void showContextualMenu(ContextualMenuParams params, Callback onButtonClicked) {
216
+        stack.peek().showContextualMenu(params, onButtonClicked);
217
+    }
218
+
212 219
     @Override
213 220
     public boolean onTitleBarBackButtonClick() {
214 221
         if (leftButtonOnClickListener != null) {

+ 33
- 0
android/app/src/main/java/com/reactnativenavigation/params/BaseTitleBarButtonParams.java 查看文件

@@ -0,0 +1,33 @@
1
+package com.reactnativenavigation.params;
2
+
3
+import android.graphics.drawable.Drawable;
4
+import android.view.MenuItem;
5
+
6
+public class BaseTitleBarButtonParams {
7
+    public enum ShowAsAction {
8
+        IfRoom(MenuItem.SHOW_AS_ACTION_IF_ROOM),
9
+        Always(MenuItem.SHOW_AS_ACTION_ALWAYS),
10
+        Never(MenuItem.SHOW_AS_ACTION_NEVER),
11
+        WithText(MenuItem.SHOW_AS_ACTION_WITH_TEXT);
12
+
13
+        public final int action;
14
+
15
+        ShowAsAction(int action) {
16
+            this.action = action;
17
+        }
18
+    }
19
+
20
+    public String eventId;
21
+    public String label;
22
+    public Drawable icon;
23
+    public StyleParams.Color color;
24
+    public StyleParams.Color disabledColor;
25
+    public ShowAsAction showAsAction;
26
+    public boolean enabled = true;
27
+
28
+    public void setColorFromScreenStyle(StyleParams.Color titleBarButtonColor) {
29
+        if (!color.hasColor() && titleBarButtonColor.hasColor()) {
30
+            color = titleBarButtonColor;
31
+        }
32
+    }
33
+}

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuButtonParams.java 查看文件

@@ -0,0 +1,5 @@
1
+package com.reactnativenavigation.params;
2
+
3
+public class ContextualMenuButtonParams extends TitleBarButtonParams {
4
+    public int index;
5
+}

+ 16
- 0
android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuParams.java 查看文件

@@ -0,0 +1,16 @@
1
+package com.reactnativenavigation.params;
2
+
3
+import java.util.List;
4
+
5
+public class ContextualMenuParams {
6
+    public List<ContextualMenuButtonParams> buttons;
7
+    public TitleBarLeftButtonParams leftButton;
8
+    public NavigationParams navigationParams;
9
+
10
+    public void setButtonsColor(StyleParams.Color buttonColor) {
11
+        for (ContextualMenuButtonParams button : buttons) {
12
+            button.setColorFromScreenStyle(buttonColor);
13
+        }
14
+        leftButton.setColorFromScreenStyle(buttonColor);
15
+    }
16
+}

+ 3
- 0
android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java 查看文件

@@ -36,6 +36,9 @@ public class StyleParams {
36 36
     }
37 37
 
38 38
     public Color statusBarColor;
39
+    public Color contextualMenuStatusBarColor;
40
+    public Color contextualMenuButtonsColor;
41
+    public Color contextualMenuBackgroundColor;
39 42
 
40 43
     public Color topBarColor;
41 44
     public boolean topBarHidden;

+ 1
- 20
android/app/src/main/java/com/reactnativenavigation/params/TitleBarButtonParams.java 查看文件

@@ -1,28 +1,9 @@
1 1
 package com.reactnativenavigation.params;
2 2
 
3
-import android.graphics.drawable.Drawable;
4
-import android.view.MenuItem;
5
-
6
-public class TitleBarButtonParams {
7
-    public enum ShowAsAction {
8
-        IfRoom(MenuItem.SHOW_AS_ACTION_IF_ROOM),
9
-        Always(MenuItem.SHOW_AS_ACTION_ALWAYS),
10
-        Never(MenuItem.SHOW_AS_ACTION_NEVER),
11
-        WithText(MenuItem.SHOW_AS_ACTION_WITH_TEXT);
12
-
13
-        public final int action;
14
-
15
-        ShowAsAction(int action) {
16
-            this.action = action;
17
-        }
18
-    }
19
-
3
+public class TitleBarButtonParams extends BaseTitleBarButtonParams {
20 4
     public String eventId;
21
-    public String label;
22
-    public Drawable icon;
23 5
     public StyleParams.Color color;
24 6
     public StyleParams.Color disabledColor;
25
-    public ShowAsAction showAsAction;
26 7
     public boolean enabled = true;
27 8
 
28 9
     public void setColorFromScreenStyle(StyleParams.Color titleBarButtonColor) {

+ 30
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuButtonParamsParser.java 查看文件

@@ -0,0 +1,30 @@
1
+package com.reactnativenavigation.params.parsers;
2
+
3
+import android.os.Bundle;
4
+
5
+import com.reactnativenavigation.params.ContextualMenuButtonParams;
6
+import com.reactnativenavigation.params.StyleParams;
7
+import com.reactnativenavigation.react.ImageLoader;
8
+
9
+import java.util.List;
10
+
11
+public class ContextualMenuButtonParamsParser extends TitleBarButtonParamsParser {
12
+    public List<ContextualMenuButtonParams> parseContextualMenuButtons(Bundle params) {
13
+        return parseBundle(params, new ParseStrategy<ContextualMenuButtonParams>() {
14
+            @Override
15
+            public ContextualMenuButtonParams parse(Bundle button) {
16
+                return parseSingleContextualMenuButton(button);
17
+            }
18
+        });
19
+    }
20
+
21
+    private ContextualMenuButtonParams parseSingleContextualMenuButton(Bundle button) {
22
+        ContextualMenuButtonParams result = new ContextualMenuButtonParams();
23
+        result.icon = ImageLoader.loadImage(button.getString("icon"));
24
+        result.showAsAction = parseShowAsAction(button.getString("showAsAction"));
25
+        result.color = StyleParams.Color.parse(button.getString("color"));
26
+        result.label = button.getString("label");
27
+        result.index = (int) button.getDouble("index");
28
+        return result;
29
+    }
30
+}

+ 16
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuParamsParser.java 查看文件

@@ -0,0 +1,16 @@
1
+package com.reactnativenavigation.params.parsers;
2
+
3
+import android.os.Bundle;
4
+
5
+import com.reactnativenavigation.params.ContextualMenuParams;
6
+import com.reactnativenavigation.params.NavigationParams;
7
+
8
+public class ContextualMenuParamsParser extends Parser {
9
+    public ContextualMenuParams parse(Bundle bundle) {
10
+        ContextualMenuParams result = new ContextualMenuParams();
11
+        result.buttons = new ContextualMenuButtonParamsParser().parseContextualMenuButtons(bundle.getBundle("buttons"));
12
+        result.leftButton = new TitleBarLeftButtonParamsParser().parseSingleButton(bundle.getBundle("backButton"));
13
+        result.navigationParams = new NavigationParams(bundle.getBundle("navigationParams"));
14
+        return result;
15
+    }
16
+}

+ 2
- 2
android/app/src/main/java/com/reactnativenavigation/params/parsers/ScreenParamsParser.java 查看文件

@@ -18,7 +18,7 @@ public class ScreenParamsParser extends Parser {
18 18
     private static final String TOP_TABS = "topTabs";
19 19
     private static final String FRAGMENT_CREATOR_CLASS_NAME = "fragmentCreatorClassName";
20 20
     private static final String FRAGMENT_CREATOR_PASS_PROPS = "fragmentCreatorPassProps";
21
-    public static final String OVERRIDE_BACK_PRESS = "overrideBackPress";
21
+    private static final String OVERRIDE_BACK_PRESS = "overrideBackPress";
22 22
 
23 23
     @SuppressWarnings("ConstantConditions")
24 24
     public static ScreenParams parse(Bundle params) {
@@ -75,7 +75,7 @@ public class ScreenParamsParser extends Parser {
75 75
         return topTabParams;
76 76
     }
77 77
 
78
-    public List<ScreenParams> parseTabs(Bundle params) {
78
+    List<ScreenParams> parseTabs(Bundle params) {
79 79
         return parseBundle(params, new ParseStrategy<ScreenParams>() {
80 80
             @Override
81 81
             public ScreenParams parse(Bundle screen) {

+ 15
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/StyleParamsParser.java 查看文件

@@ -20,6 +20,9 @@ public class StyleParamsParser {
20 20
         }
21 21
 
22 22
         result.statusBarColor = getColor("statusBarColor", getDefaultStatusBarColor());
23
+        result.contextualMenuStatusBarColor = getColor("contextualMenuStatusBarColor", getDefaultContextualMenuStatusBarColor());
24
+        result.contextualMenuButtonsColor = getColor("contextualMenuButtonsColor", getDefaultContextualMenuButtonsColor());
25
+        result.contextualMenuBackgroundColor = getColor("contextualMenuBackgroundColor", getDefaultContextualMenuBackgroundColor());
23 26
 
24 27
         result.topBarColor = getColor("topBarColor", getDefaultTopBarColor());
25 28
         result.titleBarHidden = getBoolean("titleBarHidden", getDefaultTopBarHidden());
@@ -58,6 +61,18 @@ public class StyleParamsParser {
58 61
         return result;
59 62
     }
60 63
 
64
+    private StyleParams.Color getDefaultContextualMenuStatusBarColor() {
65
+        return new StyleParams.Color(Color.parseColor("#7c7c7c"));
66
+    }
67
+
68
+    private StyleParams.Color getDefaultContextualMenuBackgroundColor() {
69
+        return new StyleParams.Color(Color.WHITE);
70
+    }
71
+
72
+    private StyleParams.Color getDefaultContextualMenuButtonsColor() {
73
+        return new StyleParams.Color(Color.parseColor("#757575"));
74
+    }
75
+
61 76
     private boolean getDefaultDrawScreenAboveBottomTabs() {
62 77
         return AppStyle.appStyle == null || AppStyle.appStyle.drawScreenAboveBottomTabs;
63 78
     }

+ 7
- 6
android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java 查看文件

@@ -3,6 +3,7 @@ package com.reactnativenavigation.params.parsers;
3 3
 import android.os.Bundle;
4 4
 
5 5
 import com.reactnativenavigation.params.AppStyle;
6
+import com.reactnativenavigation.params.BaseTitleBarButtonParams;
6 7
 import com.reactnativenavigation.params.TitleBarButtonParams;
7 8
 import com.reactnativenavigation.react.ImageLoader;
8 9
 
@@ -32,21 +33,21 @@ public class TitleBarButtonParamsParser extends Parser {
32 33
         return result;
33 34
     }
34 35
 
35
-    private static TitleBarButtonParams.ShowAsAction parseShowAsAction(String showAsAction) {
36
+    protected BaseTitleBarButtonParams.ShowAsAction parseShowAsAction(String showAsAction) {
36 37
         if (showAsAction == null) {
37
-            return TitleBarButtonParams.ShowAsAction.IfRoom;
38
+            return BaseTitleBarButtonParams.ShowAsAction.IfRoom;
38 39
         }
39 40
 
40 41
         switch (showAsAction) {
41 42
             case "always":
42
-                return TitleBarButtonParams.ShowAsAction.Always;
43
+                return BaseTitleBarButtonParams.ShowAsAction.Always;
43 44
             case "never":
44
-                return TitleBarButtonParams.ShowAsAction.Never;
45
+                return BaseTitleBarButtonParams.ShowAsAction.Never;
45 46
             case "withText":
46
-                return TitleBarButtonParams.ShowAsAction.WithText;
47
+                return BaseTitleBarButtonParams.ShowAsAction.WithText;
47 48
             case "ifRoom":
48 49
             default:
49
-                return TitleBarButtonParams.ShowAsAction.IfRoom;
50
+                return BaseTitleBarButtonParams.ShowAsAction.IfRoom;
50 51
         }
51 52
     }
52 53
 }

+ 4
- 2
android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java 查看文件

@@ -10,17 +10,18 @@ import com.facebook.react.bridge.WritableMap;
10 10
 import com.reactnativenavigation.NavigationApplication;
11 11
 import com.reactnativenavigation.events.EventBus;
12 12
 import com.reactnativenavigation.events.ScreenChangedEvent;
13
+import com.reactnativenavigation.events.ViewPagerScreenChangedEvent;
13 14
 import com.reactnativenavigation.params.PageParams;
14 15
 import com.reactnativenavigation.views.ContentView;
15 16
 
16 17
 import java.util.List;
17 18
 
18
-public class ContentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener {
19
+class ContentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener {
19 20
     private List<ContentView> contentViews;
20 21
     private List<PageParams> pageParams;
21 22
     private int currentPosition = 0;
22 23
 
23
-    public ContentViewPagerAdapter(List<ContentView> contentViews, List<PageParams> pageParams) {
24
+    ContentViewPagerAdapter(List<ContentView> contentViews, List<PageParams> pageParams) {
24 25
         this.contentViews = contentViews;
25 26
         this.pageParams = pageParams;
26 27
     }
@@ -52,6 +53,7 @@ public class ContentViewPagerAdapter extends PagerAdapter implements ViewPager.O
52 53
 
53 54
     @Override
54 55
     public void onPageSelected(int position) {
56
+        EventBus.instance.post(new ViewPagerScreenChangedEvent());
55 57
         currentPosition = position;
56 58
         EventBus.instance.post(new ScreenChangedEvent(pageParams.get(currentPosition)));
57 59
         sendTabSelectedEventToJs();

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java 查看文件

@@ -114,6 +114,11 @@ public class FragmentScreen extends Screen {
114 114
         contentView.unmountReactView();
115 115
     }
116 116
 
117
+    @Override
118
+    public String getNavigatorEventId() {
119
+        return screenParams.getNavigatorEventId();
120
+    }
121
+
117 122
     @Override
118 123
     public void setOnDisplayListener(final OnDisplayListener onContentViewDisplayedListener) {
119 124
         ViewUtils.runOnPreDraw(content, new Runnable() {

+ 33
- 4
android/app/src/main/java/com/reactnativenavigation/screens/Screen.java 查看文件

@@ -8,8 +8,15 @@ import android.support.v7.app.AppCompatActivity;
8 8
 import android.view.Window;
9 9
 import android.widget.RelativeLayout;
10 10
 
11
+import com.facebook.react.bridge.Callback;
11 12
 import com.reactnativenavigation.animation.VisibilityAnimator;
13
+import com.reactnativenavigation.events.ContextualMenuHiddenEvent;
14
+import com.reactnativenavigation.events.Event;
15
+import com.reactnativenavigation.events.EventBus;
16
+import com.reactnativenavigation.events.Subscriber;
17
+import com.reactnativenavigation.events.ViewPagerScreenChangedEvent;
12 18
 import com.reactnativenavigation.params.BaseScreenParams;
19
+import com.reactnativenavigation.params.ContextualMenuParams;
13 20
 import com.reactnativenavigation.params.ScreenParams;
14 21
 import com.reactnativenavigation.params.StyleParams;
15 22
 import com.reactnativenavigation.params.TitleBarButtonParams;
@@ -23,7 +30,7 @@ import java.util.List;
23 30
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
24 31
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
25 32
 
26
-public abstract class Screen extends RelativeLayout {
33
+public abstract class Screen extends RelativeLayout implements Subscriber {
27 34
 
28 35
     public interface OnDisplayListener {
29 36
         void onDisplay();
@@ -45,6 +52,19 @@ public abstract class Screen extends RelativeLayout {
45 52
         this.leftButtonOnClickListener = leftButtonOnClickListener;
46 53
         screenAnimator = new ScreenAnimator(this);
47 54
         createViews();
55
+        EventBus.instance.register(this);
56
+    }
57
+
58
+    @Override
59
+    public void onEvent(Event event) {
60
+        if (ContextualMenuHiddenEvent.TYPE.equals(event.getType()) && isShown()) {
61
+            setStyle();
62
+            topBar.onContextualMenuHidden();
63
+        }
64
+        if (ViewPagerScreenChangedEvent.TYPE.equals(event.getType()) && isShown() ) {
65
+            setStyle();
66
+            topBar.dismissContextualMenu();
67
+        }
48 68
     }
49 69
 
50 70
     public void setStyle() {
@@ -129,9 +149,7 @@ public abstract class Screen extends RelativeLayout {
129 149
         return screenParams.getScreenInstanceId();
130 150
     }
131 151
 
132
-    public String getNavigatorEventId() {
133
-        return screenParams.getNavigatorEventId();
134
-    }
152
+    public abstract String getNavigatorEventId();
135 153
 
136 154
     public BaseScreenParams getScreenParams() {
137 155
         return screenParams;
@@ -194,4 +212,15 @@ public abstract class Screen extends RelativeLayout {
194 212
     public void hide(boolean animated, Runnable onAnimatedEnd) {
195 213
         screenAnimator.hide(animated, onAnimatedEnd);
196 214
     }
215
+
216
+    public void showContextualMenu(ContextualMenuParams params, Callback onButtonClicked) {
217
+        params.setButtonsColor(styleParams.contextualMenuButtonsColor);
218
+        topBar.showContextualMenu(params, styleParams.contextualMenuBackgroundColor, onButtonClicked);
219
+        setStatusBarColor(styleParams.contextualMenuStatusBarColor);
220
+    }
221
+
222
+    public void destroy() {
223
+        unmountReactView();
224
+        EventBus.instance.unregister(this);
225
+    }
197 226
 }

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java 查看文件

@@ -168,7 +168,7 @@ public class ScreenStack {
168 168
 
169 169
     public void destroy() {
170 170
         for (Screen screen : stack) {
171
-            screen.unmountReactView();
171
+            screen.destroy();
172 172
             parent.removeView(screen);
173 173
         }
174 174
         stack.clear();

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java 查看文件

@@ -32,6 +32,11 @@ public class SingleScreen extends Screen {
32 32
         contentView.unmountReactView();
33 33
     }
34 34
 
35
+    @Override
36
+    public String getNavigatorEventId() {
37
+        return screenParams.getNavigatorEventId();
38
+    }
39
+
35 40
     @Override
36 41
     public void setOnDisplayListener(OnDisplayListener onContentViewDisplayedListener) {
37 42
         contentView.setOnDisplayListener(onContentViewDisplayedListener);

+ 74
- 0
android/app/src/main/java/com/reactnativenavigation/views/ContextualMenu.java 查看文件

@@ -0,0 +1,74 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.view.Menu;
5
+
6
+import com.facebook.react.bridge.Callback;
7
+import com.reactnativenavigation.NavigationApplication;
8
+import com.reactnativenavigation.events.ContextualMenuHiddenEvent;
9
+import com.reactnativenavigation.events.EventBus;
10
+import com.reactnativenavigation.params.ContextualMenuButtonParams;
11
+import com.reactnativenavigation.params.ContextualMenuParams;
12
+import com.reactnativenavigation.params.StyleParams;
13
+import com.reactnativenavigation.params.TitleBarLeftButtonParams;
14
+
15
+import java.util.List;
16
+
17
+public class ContextualMenu extends TitleBar implements LeftButtonOnClickListener, ContextualMenuButton.ContextualButtonClickListener {
18
+    private Callback onButtonClicked;
19
+    private final String navigatorEventId;
20
+
21
+    public ContextualMenu(Context context, ContextualMenuParams params, StyleParams.Color contextualMenuBackgroundColor, Callback onButtonClicked) {
22
+        super(context);
23
+        this.onButtonClicked = onButtonClicked;
24
+        navigatorEventId = params.navigationParams.navigatorEventId;
25
+        setStyle(contextualMenuBackgroundColor);
26
+        setButtons(params.buttons, params.leftButton);
27
+    }
28
+
29
+    public void setStyle(StyleParams.Color contextualMenuBackgroundColor) {
30
+        if (contextualMenuBackgroundColor.hasColor()) {
31
+            setBackgroundColor(contextualMenuBackgroundColor.getColor());
32
+        }
33
+    }
34
+
35
+    public void setButtons(List<ContextualMenuButtonParams> buttons, TitleBarLeftButtonParams leftButton) {
36
+        addButtonsToContextualMenu(buttons, getMenu());
37
+        setBackButton(leftButton);
38
+    }
39
+
40
+    private void setBackButton(TitleBarLeftButtonParams leftButton) {
41
+        setLeftButton(leftButton, this, null, false);
42
+    }
43
+
44
+    private void addButtonsToContextualMenu(List<ContextualMenuButtonParams> buttons, Menu menu) {
45
+        for (int i = 0; i < buttons.size(); i++) {
46
+            final TitleBarButton button = new ContextualMenuButton(menu, this, buttons.get(i), this);
47
+            addButtonInReverseOrder(buttons, i, button);
48
+        }
49
+    }
50
+
51
+    @Override
52
+    public boolean onTitleBarBackButtonClick() {
53
+        dismiss();
54
+        EventBus.instance.post(new ContextualMenuHiddenEvent());
55
+        return true;
56
+    }
57
+
58
+    @Override
59
+    public void onSideMenuButtonClick() {
60
+        // nothing
61
+    }
62
+
63
+    @Override
64
+    public void onClick(int index) {
65
+        dismiss();
66
+        EventBus.instance.post(new ContextualMenuHiddenEvent());
67
+        onButtonClicked.invoke(index);
68
+    }
69
+
70
+    public void dismiss() {
71
+        hide();
72
+        NavigationApplication.instance.sendNavigatorEvent("contextualMenuDismissed", navigatorEventId);
73
+    }
74
+}

+ 28
- 0
android/app/src/main/java/com/reactnativenavigation/views/ContextualMenuButton.java 查看文件

@@ -0,0 +1,28 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.view.Menu;
4
+import android.view.MenuItem;
5
+import android.view.View;
6
+
7
+import com.reactnativenavigation.params.ContextualMenuButtonParams;
8
+
9
+class ContextualMenuButton extends TitleBarButton {
10
+    private ContextualMenuButtonParams contextualMenuButtonParams;
11
+    private ContextualButtonClickListener contextualButtonClickListener;
12
+
13
+    interface ContextualButtonClickListener {
14
+        void onClick(int index);
15
+    }
16
+
17
+    ContextualMenuButton(Menu menu, View parent, ContextualMenuButtonParams contextualMenuButtonParams, ContextualButtonClickListener contextualButtonClickListener) {
18
+        super(menu, parent, contextualMenuButtonParams, null);
19
+        this.contextualMenuButtonParams = contextualMenuButtonParams;
20
+        this.contextualButtonClickListener = contextualButtonClickListener;
21
+    }
22
+
23
+    @Override
24
+    public boolean onMenuItemClick(MenuItem item) {
25
+        contextualButtonClickListener.onClick(contextualMenuButtonParams.index);
26
+        return true;
27
+    }
28
+}

+ 27
- 3
android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java 查看文件

@@ -6,8 +6,11 @@ import android.support.v7.widget.ActionMenuView;
6 6
 import android.support.v7.widget.Toolbar;
7 7
 import android.view.Menu;
8 8
 import android.view.View;
9
+import android.view.animation.AccelerateDecelerateInterpolator;
10
+import android.view.animation.AccelerateInterpolator;
9 11
 
10 12
 import com.reactnativenavigation.animation.VisibilityAnimator;
13
+import com.reactnativenavigation.params.BaseTitleBarButtonParams;
11 14
 import com.reactnativenavigation.params.StyleParams;
12 15
 import com.reactnativenavigation.params.TitleBarButtonParams;
13 16
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
@@ -46,7 +49,9 @@ public class TitleBar extends Toolbar {
46 49
     }
47 50
 
48 51
     public void setLeftButton(TitleBarLeftButtonParams leftButtonParams,
49
-                              LeftButtonOnClickListener leftButtonOnClickListener, String navigatorEventId, boolean overrideBackPressInJs) {
52
+                              LeftButtonOnClickListener leftButtonOnClickListener,
53
+                              String navigatorEventId,
54
+                              boolean overrideBackPressInJs) {
50 55
         if (shouldSetLeftButton(leftButtonParams)) {
51 56
             createAndSetLeftButton(leftButtonParams, leftButtonOnClickListener, navigatorEventId, overrideBackPressInJs);
52 57
         } else if (hasLeftButton()) {
@@ -91,8 +96,8 @@ public class TitleBar extends Toolbar {
91 96
         }
92 97
     }
93 98
 
94
-    private void addButtonInReverseOrder(List<TitleBarButtonParams> rightButtons, int i, TitleBarButton button) {
95
-        final int index = rightButtons.size() - i - 1;
99
+    protected void addButtonInReverseOrder(List<? extends BaseTitleBarButtonParams> buttons, int i, TitleBarButton button) {
100
+        final int index = buttons.size() - i - 1;
96 101
         button.addToMenu(index);
97 102
     }
98 103
 
@@ -134,4 +139,23 @@ public class TitleBar extends Toolbar {
134 139
     private void createScrollAnimator() {
135 140
         visibilityAnimator = new VisibilityAnimator(this, VisibilityAnimator.HideDirection.Up, getHeight());
136 141
     }
142
+
143
+    public void hide() {
144
+        animate()
145
+                .alpha(0)
146
+                .setDuration(200)
147
+                .setInterpolator(new AccelerateInterpolator());
148
+    }
149
+
150
+    public void show() {
151
+        if (getAlpha() == 1) {
152
+            return;
153
+        }
154
+
155
+        setAlpha(0);
156
+        animate()
157
+                .alpha(1)
158
+                .setDuration(200)
159
+                .setInterpolator(new AccelerateDecelerateInterpolator());
160
+    }
137 161
 }

+ 6
- 5
android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java 查看文件

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.views;
2 2
 
3 3
 import android.support.annotation.NonNull;
4
+import android.support.annotation.Nullable;
4 5
 import android.view.Menu;
5 6
 import android.view.MenuItem;
6 7
 import android.view.View;
@@ -12,21 +13,21 @@ import com.reactnativenavigation.utils.ViewUtils;
12 13
 
13 14
 import java.util.ArrayList;
14 15
 
15
-public class TitleBarButton implements MenuItem.OnMenuItemClickListener {
16
+class TitleBarButton implements MenuItem.OnMenuItemClickListener {
16 17
 
17 18
     private final Menu menu;
18 19
     private final View parent;
19
-    private TitleBarButtonParams buttonParams;
20
-    private String navigatorEventId;
20
+    protected TitleBarButtonParams buttonParams;
21
+    @Nullable private String navigatorEventId;
21 22
 
22
-    public TitleBarButton(Menu menu, View parent, TitleBarButtonParams buttonParams, String navigatorEventId) {
23
+    TitleBarButton(Menu menu, View parent, TitleBarButtonParams buttonParams, @Nullable String navigatorEventId) {
23 24
         this.menu = menu;
24 25
         this.parent = parent;
25 26
         this.buttonParams = buttonParams;
26 27
         this.navigatorEventId = navigatorEventId;
27 28
     }
28 29
 
29
-    public MenuItem addToMenu(int index) {
30
+    MenuItem addToMenu(int index) {
30 31
         MenuItem item = menu.add(Menu.NONE, Menu.NONE, index, buttonParams.label);
31 32
         item.setShowAsAction(buttonParams.showAsAction.action);
32 33
         item.setEnabled(buttonParams.enabled);

+ 40
- 2
android/app/src/main/java/com/reactnativenavigation/views/TopBar.java 查看文件

@@ -5,7 +5,11 @@ import android.graphics.Color;
5 5
 import android.os.Build;
6 6
 import android.support.design.widget.AppBarLayout;
7 7
 import android.support.design.widget.TabLayout;
8
+import android.view.ViewGroup;
9
+import android.widget.RelativeLayout;
8 10
 
11
+import com.facebook.react.bridge.Callback;
12
+import com.reactnativenavigation.params.ContextualMenuParams;
9 13
 import com.reactnativenavigation.params.StyleParams;
10 14
 import com.reactnativenavigation.params.TitleBarButtonParams;
11 15
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
@@ -13,15 +17,26 @@ import com.reactnativenavigation.utils.ViewUtils;
13 17
 
14 18
 import java.util.List;
15 19
 
20
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
21
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
22
+
16 23
 public class TopBar extends AppBarLayout {
17 24
 
18 25
     private TitleBar titleBar;
26
+    private ContextualMenu contextualMenu;
27
+    private RelativeLayout titleBarAndContextualMenuContainer;
19 28
     private TopTabs topTabs;
20 29
 
21 30
     public TopBar(Context context) {
22 31
         super(context);
23 32
         setFitsSystemWindows(true);
24 33
         setId(ViewUtils.generateViewId());
34
+        createLayout();
35
+    }
36
+
37
+    private void createLayout() {
38
+        titleBarAndContextualMenuContainer = new RelativeLayout(getContext());
39
+        addView(titleBarAndContextualMenuContainer);
25 40
     }
26 41
 
27 42
     public void addTitleBarAndSetButtons(List<TitleBarButtonParams> rightButtons,
@@ -29,7 +44,7 @@ public class TopBar extends AppBarLayout {
29 44
                                          LeftButtonOnClickListener leftButtonOnClickListener,
30 45
                                          String navigatorEventId, boolean overrideBackPressInJs) {
31 46
         titleBar = new TitleBar(getContext());
32
-        addView(titleBar);
47
+        titleBarAndContextualMenuContainer.addView(titleBar, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
33 48
         titleBar.setRightButtons(rightButtons, navigatorEventId);
34 49
         titleBar.setLeftButton(leftButton, leftButtonOnClickListener, navigatorEventId, overrideBackPressInJs);
35 50
     }
@@ -84,8 +99,31 @@ public class TopBar extends AppBarLayout {
84 99
         if (topTabs == null) {
85 100
             return;
86 101
         }
87
-
88 102
         topTabs.setTopTabsTextColor(style);
89 103
         topTabs.setSelectedTabIndicatorStyle(style);
90 104
     }
105
+
106
+    public void showContextualMenu(final ContextualMenuParams params, StyleParams.Color contextualMenuBackgroundColor, Callback onButtonClicked) {
107
+        contextualMenu = new ContextualMenu(getContext(), params, contextualMenuBackgroundColor, onButtonClicked);
108
+        titleBarAndContextualMenuContainer.addView(contextualMenu, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
109
+        ViewUtils.runOnPreDraw(contextualMenu, new Runnable() {
110
+            @Override
111
+            public void run() {
112
+                titleBar.hide();
113
+                contextualMenu.show();
114
+            }
115
+        });
116
+    }
117
+
118
+    public void onContextualMenuHidden() {
119
+        titleBar.show();
120
+    }
121
+
122
+    public void dismissContextualMenu() {
123
+        if (contextualMenu != null) {
124
+            contextualMenu.dismiss();
125
+            contextualMenu = null;
126
+            titleBar.show();
127
+        }
128
+    }
91 129
 }

+ 4
- 0
src/Screen.js 查看文件

@@ -110,6 +110,10 @@ class Navigator {
110 110
     return platformSpecific.showSnackbar(this, params);
111 111
   }
112 112
 
113
+  showContextualMenu(params, onButtonPressed) {
114
+    return platformSpecific.showContextualMenu(this, params, onButtonPressed);
115
+  }
116
+
113 117
   setOnNavigatorEvent(callback) {
114 118
     this.navigatorEventHandler = callback;
115 119
     if (!this.navigatorEventSubscription) {

+ 23
- 3
src/deprecated/platformSpecificDeprecated.android.js 查看文件

@@ -1,6 +1,6 @@
1 1
 /*eslint-disable*/
2 2
 import React, {Component} from 'react';
3
-import {AppRegistry, NativeModules} from 'react-native';
3
+import {AppRegistry, NativeModules, processColor} from 'react-native';
4 4
 import _ from 'lodash';
5 5
 
6 6
 import Navigation from './../Navigation';
@@ -420,7 +420,6 @@ function addTitleBarBackButtonIfNeeded(screen) {
420 420
 function getLeftButton(screen) {
421 421
   const leftButton = getLeftButtonDeprecated(screen);
422 422
   if (leftButton) {
423
-    console.warn('leftButton is deprecated. Instead, please use leftButtons like on iOS.');
424 423
     return leftButton;
425 424
   }
426 425
 
@@ -464,6 +463,26 @@ function showSnackbar(navigator, params) {
464 463
   return newPlatformSpecific.showSnackbar(params);
465 464
 }
466 465
 
466
+function showContextualMenu(navigator, params, onButtonPressed) {
467
+  const contextualMenu = {
468
+    buttons: [],
469
+    backButton: {id: 'back'},
470
+    navigationParams: {navigatorEventID: navigator.navigatorEventID}
471
+  };
472
+
473
+  params.rightButtons.forEach((button, index) => {
474
+    const btn = {
475
+      icon: resolveAssetSource(button.icon).uri,
476
+      color: processColor(button.color),
477
+      label: button.title,
478
+      index
479
+    };
480
+    contextualMenu.buttons.push(btn);
481
+  });
482
+
483
+  newPlatformSpecific.showContextualMenu(contextualMenu, onButtonPressed);
484
+}
485
+
467 486
 export default {
468 487
   startTabBasedApp,
469 488
   startSingleScreenApp,
@@ -482,5 +501,6 @@ export default {
482 501
   navigatorToggleDrawer,
483 502
   navigatorToggleTabs,
484 503
   navigatorToggleNavBar,
485
-  showSnackbar
504
+  showSnackbar,
505
+  showContextualMenu
486 506
 };

+ 6
- 1
src/platformSpecific.android.js 查看文件

@@ -120,6 +120,10 @@ function showSnackbar(params) {
120 120
   NativeReactModule.showSnackbar(params);
121 121
 }
122 122
 
123
+function showContextualMenu(params, onButtonPressed) {
124
+  NativeReactModule.showContextualMenu(params, onButtonPressed);
125
+}
126
+
123 127
 module.exports = {
124 128
   startApp,
125 129
   push,
@@ -140,5 +144,6 @@ module.exports = {
140 144
   selectBottomTabByTabIndex,
141 145
   setBottomTabBadgeByNavigatorId,
142 146
   setBottomTabBadgeByIndex,
143
-  showSnackbar
147
+  showSnackbar,
148
+  showContextualMenu
144 149
 };