浏览代码

[Breaking] Top bar API changes (#2895)

* Refactor TopBar options, introduce title options

* Update background to new api

* Refactored topBar options on iOS

* Initial react component in TitleBar android

* set height to react view in TitleBar

* fix tests and lint

* ios unit tests fix
Guy Carmeli 6 年前
父节点
当前提交
2c53b28660
没有帐户链接到提交者的电子邮件
共有 56 个文件被更改,包括 657 次插入306 次删除
  1. 4
    1
      e2e/Orientations.test.js
  2. 7
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  3. 75
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TitleOptions.java
  4. 30
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarBackground.java
  5. 22
    71
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java
  6. 6
    5
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  7. 6
    3
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  8. 36
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewController.java
  9. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TopBarButtonController.java
  10. 3
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java
  11. 17
    4
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  12. 0
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBarButtonCreator.java
  13. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBarReactButtonView.java
  14. 16
    7
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java
  15. 15
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactView.java
  16. 20
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactViewCreator.java
  17. 20
    0
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java
  18. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopBarButtonCreatorMock.java
  19. 31
    21
      lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java
  20. 7
    2
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java
  21. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java
  22. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/FloatingActionButtonTest.java
  23. 7
    6
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java
  24. 16
    15
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  25. 12
    7
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java
  26. 13
    8
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  27. 16
    2
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java
  28. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopBarButtonControllerTest.java
  29. 12
    6
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  30. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java
  31. 3
    2
      lib/android/app/src/test/java/com/reactnativenavigation/views/TopBarTest.java
  32. 5
    2
      lib/ios/RNNCustomTitleView.h
  33. 41
    33
      lib/ios/RNNCustomTitleView.m
  34. 6
    1
      lib/ios/RNNOptions.m
  35. 17
    6
      lib/ios/RNNRootViewController.m
  36. 13
    0
      lib/ios/RNNTitleOptions.h
  37. 32
    0
      lib/ios/RNNTitleOptions.m
  38. 4
    6
      lib/ios/RNNTopBarOptions.h
  39. 9
    25
      lib/ios/RNNTopBarOptions.m
  40. 8
    0
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  41. 1
    1
      lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m
  42. 2
    2
      lib/ios/ReactNativeNavigationTests/RNNNavigationOptionsTest.m
  43. 12
    12
      lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m
  44. 4
    2
      lib/src/commands/LayoutTreeParser.test.ts
  45. 3
    1
      playground/src/screens/BackHandlerModalScreen.js
  46. 5
    3
      playground/src/screens/BackHandlerScreen.js
  47. 1
    1
      playground/src/screens/CustomTopBar.js
  48. 4
    2
      playground/src/screens/CustomTransitionDestination.js
  49. 4
    2
      playground/src/screens/CustomTransitionOrigin.js
  50. 27
    13
      playground/src/screens/OptionsScreen.js
  51. 3
    1
      playground/src/screens/PushedScreen.js
  52. 5
    3
      playground/src/screens/ScrollViewScreen.js
  53. 11
    7
      playground/src/screens/TopTabOptionsScreen.js
  54. 5
    3
      playground/src/screens/TopTabScreen.js
  55. 28
    9
      playground/src/screens/WelcomeScreen.js
  56. 1
    0
      playground/src/testIDs.js

+ 4
- 1
e2e/Orientations.test.js 查看文件

@@ -8,14 +8,16 @@ describe('orientation', () => {
8 8
 
9 9
   beforeEach(async () => {
10 10
     await device.relaunchApp();
11
-    waitForDeviceToSettleAfterOrientationChangeAndroid = ms => new Promise(res => setTimeout(res, device.getPlatform() === 'ios' ? 0 : 150));
11
+    waitForDeviceToSettleAfterOrientationChangeAndroid = ms => new Promise(res => setTimeout(res, device.getPlatform() === 'ios' ? 0 : 400));
12 12
   });
13 13
 
14 14
   it('default allows all', async () => {
15 15
     await elementById(testIDs.ORIENTATION_BUTTON).tap();
16 16
     await elementById(testIDs.DEFAULT_ORIENTATION_BUTTON).tap();
17
+    waitForDeviceToSettleAfterOrientationChangeAndroid();
17 18
     await expect(elementById(testIDs.PORTRAIT_ELEMENT)).toBeVisible();
18 19
     await device.setOrientation('landscape');
20
+    waitForDeviceToSettleAfterOrientationChangeAndroid();
19 21
     await expect(elementById(testIDs.LANDSCAPE_ELEMENT)).toBeVisible();
20 22
     await device.setOrientation('portrait');
21 23
     waitForDeviceToSettleAfterOrientationChangeAndroid();
@@ -28,6 +30,7 @@ describe('orientation', () => {
28 30
     await elementById(testIDs.LANDSCAPE_PORTRAIT_ORIENTATION_BUTTON).tap();
29 31
     await expect(element(by.id(testIDs.PORTRAIT_ELEMENT))).toBeVisible();
30 32
     await device.setOrientation('landscape');
33
+    waitForDeviceToSettleAfterOrientationChangeAndroid();
31 34
     await expect(element(by.id(testIDs.LANDSCAPE_ELEMENT))).toBeVisible();
32 35
     await device.setOrientation('portrait');
33 36
     waitForDeviceToSettleAfterOrientationChangeAndroid();

+ 7
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java 查看文件

@@ -15,6 +15,7 @@ import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalCompo
15 15
 import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentViewController;
16 16
 import com.reactnativenavigation.viewcontrollers.toptabs.TopTabsController;
17 17
 import com.reactnativenavigation.views.ComponentViewCreator;
18
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
18 19
 import com.reactnativenavigation.views.TopBarButtonCreator;
19 20
 import com.reactnativenavigation.views.TopTabsLayoutCreator;
20 21
 
@@ -118,7 +119,12 @@ public class LayoutFactory {
118 119
     }
119 120
 
120 121
 	private ViewController createStack(LayoutNode node) {
121
-        StackController stackController = new StackController(activity, new TopBarButtonCreator(reactInstanceManager), node.id, getOptions(node));
122
+        StackController stackController = new StackController(activity,
123
+                new TopBarButtonCreator(reactInstanceManager),
124
+                new TitleBarReactViewCreator(reactInstanceManager),
125
+                node.id,
126
+                getOptions(node)
127
+        );
122 128
         addChildrenToStack(node.children, stackController);
123 129
         return stackController;
124 130
 	}

+ 75
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/TitleOptions.java 查看文件

@@ -0,0 +1,75 @@
1
+package com.reactnativenavigation.parse;
2
+
3
+import android.graphics.Typeface;
4
+import android.support.annotation.Nullable;
5
+
6
+import com.reactnativenavigation.parse.params.Color;
7
+import com.reactnativenavigation.parse.params.Fraction;
8
+import com.reactnativenavigation.parse.params.NullColor;
9
+import com.reactnativenavigation.parse.params.NullFraction;
10
+import com.reactnativenavigation.parse.params.NullText;
11
+import com.reactnativenavigation.parse.params.Text;
12
+import com.reactnativenavigation.parse.parsers.ColorParser;
13
+import com.reactnativenavigation.parse.parsers.FractionParser;
14
+import com.reactnativenavigation.parse.parsers.TextParser;
15
+import com.reactnativenavigation.utils.TypefaceLoader;
16
+
17
+import org.json.JSONObject;
18
+
19
+public class TitleOptions {
20
+    public enum Alignment {
21
+        Center, Fill, Default;
22
+
23
+        public static Alignment fromString(String alignment) {
24
+            switch (alignment) {
25
+                case "center":
26
+                    return Center;
27
+                case "fill":
28
+                    return Fill;
29
+                default:
30
+                    return Default;
31
+            }
32
+        }
33
+    }
34
+
35
+    public static TitleOptions parse(TypefaceLoader typefaceManager, JSONObject json) {
36
+        final TitleOptions options = new TitleOptions();
37
+        if (json == null) {
38
+            return options;
39
+        }
40
+
41
+        options.text = TextParser.parse(json, "text");
42
+        options.color = ColorParser.parse(json, "color");
43
+        options.fontSize = FractionParser.parse(json, "fontSize");
44
+        options.fontFamily = typefaceManager.getTypeFace(json.optString("fontFamily", ""));
45
+        options.component = TextParser.parse(json, "component");
46
+        options.alignment = Alignment.fromString(TextParser.parse(json, "alignment").get(""));
47
+
48
+        return options;
49
+    }
50
+
51
+    public Text text = new NullText();
52
+    public Color color = new NullColor();
53
+    public Fraction fontSize = new NullFraction();
54
+    @Nullable public Typeface fontFamily;
55
+    public Text component = new NullText();
56
+    public Alignment alignment = Alignment.Default;
57
+
58
+    void mergeWith(final TitleOptions other) {
59
+        if (other.text.hasValue()) text = other.text;
60
+        if (other.color.hasValue()) color = other.color;
61
+        if (other.fontSize.hasValue()) fontSize = other.fontSize;
62
+        if (other.fontFamily != null) fontFamily = other.fontFamily;
63
+        if (other.component.hasValue()) component = other.component;
64
+        if (other.alignment != Alignment.Default) alignment = other.alignment;
65
+    }
66
+
67
+    void mergeWithDefault(TitleOptions defaultOptions) {
68
+        if (!text.hasValue()) text = defaultOptions.text;
69
+        if (!color.hasValue()) color = defaultOptions.color;
70
+        if (!fontSize.hasValue()) fontSize = defaultOptions.fontSize;
71
+        if (fontFamily == null) fontFamily = defaultOptions.fontFamily;
72
+        if (!component.hasValue()) component = defaultOptions.component;
73
+        if (alignment == Alignment.Default) alignment = defaultOptions.alignment;
74
+    }
75
+}

+ 30
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarBackground.java 查看文件

@@ -0,0 +1,30 @@
1
+package com.reactnativenavigation.parse;
2
+
3
+import com.reactnativenavigation.parse.params.Color;
4
+import com.reactnativenavigation.parse.params.NullColor;
5
+import com.reactnativenavigation.parse.parsers.ColorParser;
6
+
7
+import org.json.JSONObject;
8
+
9
+public class TopBarBackground {
10
+    public static TopBarBackground parse(JSONObject json) {
11
+        TopBarBackground options = new TopBarBackground();
12
+        if (json == null) {
13
+            return options;
14
+        }
15
+
16
+        options.color = ColorParser.parse(json, "color");
17
+
18
+        return options;
19
+    }
20
+
21
+    public Color color = new NullColor();
22
+
23
+    void mergeWith(final TopBarBackground other) {
24
+        if (other.color.hasValue()) color = other.color;
25
+    }
26
+
27
+    void mergeWithDefault(TopBarBackground defaultOptions) {
28
+        if (!color.hasValue()) color = defaultOptions.color;
29
+    }
30
+}

+ 22
- 71
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java 查看文件

@@ -1,21 +1,14 @@
1 1
 package com.reactnativenavigation.parse;
2 2
 
3 3
 
4
-import android.graphics.Typeface;
5 4
 import android.support.annotation.Nullable;
6 5
 
7 6
 import com.reactnativenavigation.parse.params.Bool;
8 7
 import com.reactnativenavigation.parse.params.Button;
9
-import com.reactnativenavigation.parse.params.Color;
10
-import com.reactnativenavigation.parse.params.Fraction;
11 8
 import com.reactnativenavigation.parse.params.NullBool;
12
-import com.reactnativenavigation.parse.params.NullColor;
13
-import com.reactnativenavigation.parse.params.NullFraction;
14 9
 import com.reactnativenavigation.parse.params.NullText;
15 10
 import com.reactnativenavigation.parse.params.Text;
16 11
 import com.reactnativenavigation.parse.parsers.BoolParser;
17
-import com.reactnativenavigation.parse.parsers.ColorParser;
18
-import com.reactnativenavigation.parse.parsers.FractionParser;
19 12
 import com.reactnativenavigation.parse.parsers.TextParser;
20 13
 import com.reactnativenavigation.utils.TypefaceLoader;
21 14
 
@@ -29,11 +22,8 @@ public class TopBarOptions implements DEFAULT_VALUES {
29 22
         TopBarOptions options = new TopBarOptions();
30 23
         if (json == null) return options;
31 24
 
32
-        options.title = TextParser.parse(json, "title");
33
-        options.backgroundColor = ColorParser.parse(json, "backgroundColor");
34
-        options.textColor = ColorParser.parse(json, "textColor");
35
-        options.textFontSize = FractionParser.parse(json, "textFontSize");
36
-        options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", ""));
25
+        options.title = TitleOptions.parse(typefaceManager, json.optJSONObject("title"));
26
+        options.background = TopBarBackground.parse(json.optJSONObject("background"));
37 27
         options.visible = BoolParser.parse(json, "visible");
38 28
         options.animate = BoolParser.parse(json,"animate");
39 29
         options.hideOnScroll = BoolParser.parse(json,"hideOnScroll");
@@ -45,12 +35,9 @@ public class TopBarOptions implements DEFAULT_VALUES {
45 35
         return options;
46 36
     }
47 37
 
48
-    public Text title = new NullText();
38
+    public TitleOptions title = new TitleOptions();
49 39
     public Text testId = new NullText();
50
-    public Color backgroundColor = new NullColor();
51
-    public Color textColor = new NullColor();
52
-    public Fraction textFontSize = new NullFraction();
53
-    @Nullable public Typeface textFontFamily;
40
+    public TopBarBackground background = new TopBarBackground();
54 41
     public Bool visible = new NullBool();
55 42
     public Bool animate = new NullBool();
56 43
     public Bool hideOnScroll = new NullBool();
@@ -59,62 +46,26 @@ public class TopBarOptions implements DEFAULT_VALUES {
59 46
     @Nullable public ArrayList<Button> rightButtons;
60 47
 
61 48
     void mergeWith(final TopBarOptions other) {
62
-        if (other.testId.hasValue()) {
63
-            testId = other.testId;
64
-        }
65
-        if (other.title.hasValue())
66
-            title = other.title;
67
-        if (other.backgroundColor.hasValue())
68
-            backgroundColor = other.backgroundColor;
69
-        if (other.textColor.hasValue())
70
-            textColor = other.textColor;
71
-        if (other.textFontSize.hasValue())
72
-            textFontSize = other.textFontSize;
73
-        if (other.textFontFamily != null)
74
-            textFontFamily = other.textFontFamily;
75
-        if (other.visible.hasValue()) {
76
-            visible = other.visible;
77
-        }
78
-        if (other.animate.hasValue()) {
79
-            animate = other.animate;
80
-        }
81
-        if (other.hideOnScroll.hasValue()) {
82
-            hideOnScroll = other.hideOnScroll;
83
-        }
84
-        if (other.drawBehind.hasValue()) {
85
-            drawBehind = other.drawBehind;
86
-        }
87
-        if (other.leftButtons != null)
88
-            leftButtons = other.leftButtons;
89
-        if (other.rightButtons != null)
90
-            rightButtons = other.rightButtons;
49
+        title.mergeWith(other.title);
50
+        background.mergeWith(other.background);
51
+        if (other.testId.hasValue()) testId = other.testId;
52
+        if (other.visible.hasValue()) visible = other.visible;
53
+        if (other.animate.hasValue()) animate = other.animate;
54
+        if (other.hideOnScroll.hasValue()) hideOnScroll = other.hideOnScroll;
55
+        if (other.drawBehind.hasValue()) drawBehind = other.drawBehind;
56
+        if (other.leftButtons != null) leftButtons = other.leftButtons;
57
+        if (other.rightButtons != null) rightButtons = other.rightButtons;
91 58
     }
92 59
 
93 60
     void mergeWithDefault(TopBarOptions defaultOptions) {
94
-        if (title == null)
95
-            title = defaultOptions.title;
96
-        if (!backgroundColor.hasValue())
97
-            backgroundColor = defaultOptions.backgroundColor;
98
-        if (!textColor.hasValue())
99
-            textColor = defaultOptions.textColor;
100
-        if (!textFontSize.hasValue())
101
-            textFontSize = defaultOptions.textFontSize;
102
-        if (textFontFamily == null)
103
-            textFontFamily = defaultOptions.textFontFamily;
104
-        if (!visible.hasValue())
105
-            visible = defaultOptions.visible;
106
-        if (!animate.hasValue())
107
-            animate = defaultOptions.animate;
108
-        if (!hideOnScroll.hasValue())
109
-            hideOnScroll = defaultOptions.hideOnScroll;
110
-        if (!drawBehind.hasValue())
111
-            drawBehind = defaultOptions.drawBehind;
112
-        if (leftButtons == null)
113
-            leftButtons = defaultOptions.leftButtons;
114
-        if (rightButtons == null)
115
-            rightButtons = defaultOptions.rightButtons;
116
-        if (!testId.hasValue()) {
117
-            testId = defaultOptions.testId;
118
-        }
61
+        title.mergeWithDefault(defaultOptions.title);
62
+        background.mergeWithDefault(defaultOptions.background);
63
+        if (!visible.hasValue()) visible = defaultOptions.visible;
64
+        if (!animate.hasValue()) animate = defaultOptions.animate;
65
+        if (!hideOnScroll.hasValue()) hideOnScroll = defaultOptions.hideOnScroll;
66
+        if (!drawBehind.hasValue()) drawBehind = defaultOptions.drawBehind;
67
+        if (leftButtons == null) leftButtons = defaultOptions.leftButtons;
68
+        if (rightButtons == null) rightButtons = defaultOptions.rightButtons;
69
+        if (!testId.hasValue()) testId = defaultOptions.testId;
119 70
     }
120 71
 }

+ 6
- 5
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java 查看文件

@@ -40,13 +40,14 @@ public class OptionsPresenter {
40 40
     }
41 41
 
42 42
     private void applyTopBarOptions(TopBarOptions options) {
43
-        if (options.title.hasValue()) topBar.setTitle(options.title.get());
44
-        topBar.setBackgroundColor(options.backgroundColor);
45
-        topBar.setTitleTextColor(options.textColor);
46
-        topBar.setTitleFontSize(options.textFontSize);
43
+        if (options.title.text.hasValue()) topBar.setTitle(options.title.text.get());
44
+        if (options.title.component.hasValue()) topBar.setComponent(options.title.component.get(), options.title.alignment);
45
+        topBar.setBackgroundColor(options.background.color);
46
+        topBar.setTitleTextColor(options.title.color);
47
+        topBar.setTitleFontSize(options.title.fontSize);
47 48
         if (options.testId.hasValue()) topBar.setTestId(options.testId.get());
48 49
 
49
-        topBar.setTitleTypeface(options.textFontFamily);
50
+        topBar.setTitleTypeface(options.title.fontFamily);
50 51
         if (options.visible.isFalse()) {
51 52
             topBar.hide(options.animate);
52 53
         }

+ 6
- 3
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java 查看文件

@@ -14,6 +14,7 @@ import com.reactnativenavigation.views.Component;
14 14
 import com.reactnativenavigation.views.ReactComponent;
15 15
 import com.reactnativenavigation.views.StackLayout;
16 16
 import com.reactnativenavigation.views.TopBar;
17
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
17 18
 
18 19
 import java.util.Collection;
19 20
 import java.util.Iterator;
@@ -25,12 +26,14 @@ public class StackController extends ParentController <StackLayout> {
25 26
     private static final NoOpPromise NO_OP = new NoOpPromise();
26 27
     private final IdStack<ViewController> stack = new IdStack<>();
27 28
     private final NavigationAnimator animator;
28
-    private ReactViewCreator topBarButtonCreator;
29
+    private final ReactViewCreator topBarButtonCreator;
30
+    private final TitleBarReactViewCreator titleBarReactViewCreator;
29 31
 
30
-    public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, String id, Options initialOptions) {
32
+    public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, String id, Options initialOptions) {
31 33
         super(activity, id, initialOptions);
32 34
         animator = new NavigationAnimator(activity);
33 35
         this.topBarButtonCreator = topBarButtonCreator;
36
+        this.titleBarReactViewCreator = titleBarReactViewCreator;
34 37
     }
35 38
 
36 39
     public void applyOptions(Options options) {
@@ -202,7 +205,7 @@ public class StackController extends ParentController <StackLayout> {
202 205
     @NonNull
203 206
     @Override
204 207
     protected StackLayout createView() {
205
-        return new StackLayout(getActivity(), topBarButtonCreator, this::sendOnNavigationButtonPressed);
208
+        return new StackLayout(getActivity(), topBarButtonCreator, titleBarReactViewCreator, this::sendOnNavigationButtonPressed);
206 209
     }
207 210
 
208 211
 	@NonNull

+ 36
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewController.java 查看文件

@@ -0,0 +1,36 @@
1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.app.Activity;
4
+
5
+import com.reactnativenavigation.parse.Options;
6
+import com.reactnativenavigation.parse.TitleOptions;
7
+import com.reactnativenavigation.utils.CompatUtils;
8
+import com.reactnativenavigation.views.titlebar.TitleBarReactView;
9
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
10
+
11
+public class TitleBarReactViewController extends ViewController<TitleBarReactView> {
12
+
13
+    private final TitleBarReactViewCreator reactViewCreator;
14
+    private String componentName;
15
+    private TitleOptions.Alignment alignment;
16
+
17
+    public TitleBarReactViewController(Activity activity, TitleBarReactViewCreator reactViewCreator) {
18
+        super(activity, CompatUtils.generateViewId() + "", new Options());
19
+        this.reactViewCreator = reactViewCreator;
20
+    }
21
+
22
+    @Override
23
+    protected TitleBarReactView createView() {
24
+        return reactViewCreator.create(getActivity(), getId(), componentName);
25
+    }
26
+
27
+    @Override
28
+    public void sendOnNavigationButtonPressed(String buttonId) {
29
+
30
+    }
31
+
32
+    public void setComponent(String componentName, TitleOptions.Alignment alignment) {
33
+        this.componentName = componentName;
34
+        this.alignment = alignment;
35
+    }
36
+}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TopBarButtonController.java 查看文件

@@ -18,7 +18,7 @@ import android.widget.TextView;
18 18
 import com.reactnativenavigation.parse.Options;
19 19
 import com.reactnativenavigation.parse.params.Button;
20 20
 import com.reactnativenavigation.parse.params.Text;
21
-import com.reactnativenavigation.react.TopBarReactButtonView;
21
+import com.reactnativenavigation.views.TopBarReactButtonView;
22 22
 import com.reactnativenavigation.utils.ArrayUtils;
23 23
 import com.reactnativenavigation.utils.ImageLoader;
24 24
 import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;

+ 3
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java 查看文件

@@ -11,6 +11,7 @@ import com.reactnativenavigation.presentation.OptionsPresenter;
11 11
 import com.reactnativenavigation.utils.CompatUtils;
12 12
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
13 13
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
14
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
14 15
 
15 16
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
16 17
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -19,9 +20,9 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
19 20
 public class StackLayout extends RelativeLayout {
20 21
     private TopBar topBar;
21 22
 
22
-    public StackLayout(Context context, ReactViewCreator topBarButtonCreator, TopBarButtonController.OnClickListener topBarButtonClickListener) {
23
+    public StackLayout(Context context, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarButtonController.OnClickListener topBarButtonClickListener) {
23 24
         super(context);
24
-        topBar = new TopBar(context, topBarButtonCreator, topBarButtonClickListener, this);
25
+        topBar = new TopBar(context, topBarButtonCreator, titleBarReactViewCreator, topBarButtonClickListener, this);
25 26
         topBar.setId(CompatUtils.generateViewId());
26 27
         addView(topBar, MATCH_PARENT, WRAP_CONTENT);
27 28
         setContentDescription("StackLayout");

+ 17
- 4
lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java 查看文件

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.views;
2 2
 
3 3
 import android.annotation.SuppressLint;
4
+import android.app.Activity;
4 5
 import android.content.Context;
5 6
 import android.graphics.Typeface;
6 7
 import android.support.annotation.RestrictTo;
@@ -14,13 +15,17 @@ import android.widget.TextView;
14 15
 import com.reactnativenavigation.anim.TopBarAnimator;
15 16
 import com.reactnativenavigation.anim.TopBarCollapseBehavior;
16 17
 import com.reactnativenavigation.interfaces.ScrollEventListener;
18
+import com.reactnativenavigation.parse.TitleOptions;
17 19
 import com.reactnativenavigation.parse.params.Bool;
18 20
 import com.reactnativenavigation.parse.params.Button;
19 21
 import com.reactnativenavigation.parse.params.Color;
20 22
 import com.reactnativenavigation.parse.params.Fraction;
21 23
 import com.reactnativenavigation.parse.params.Number;
22 24
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
25
+import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
23 26
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
27
+import com.reactnativenavigation.views.titlebar.TitleBar;
28
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
24 29
 
25 30
 import java.util.List;
26 31
 
@@ -35,19 +40,23 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
35 40
     private TopTabs topTabs;
36 41
     private StackLayout parentView;
37 42
 
38
-    public TopBar(final Context context, ReactViewCreator buttonCreator, TopBarButtonController.OnClickListener onClickListener, StackLayout parentView) {
43
+    public TopBar(final Context context, ReactViewCreator buttonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarButtonController.OnClickListener onClickListener, StackLayout parentView) {
39 44
         super(context);
40 45
         collapsingBehavior = new TopBarCollapseBehavior(this);
41 46
         topTabs = new TopTabs(getContext());
42 47
         animator = new TopBarAnimator(this);
43 48
         this.parentView = parentView;
44
-        titleBar = createTitleBar(context, buttonCreator, onClickListener);
49
+        titleBar = createTitleBar(context, buttonCreator, titleBarReactViewCreator, onClickListener);
45 50
         addView(titleBar);
46 51
         setContentDescription("TopBar");
47 52
     }
48 53
 
49
-    protected TitleBar createTitleBar(Context context, ReactViewCreator buttonCreator, TopBarButtonController.OnClickListener onClickListener) {
50
-        return new TitleBar(context, buttonCreator, onClickListener);
54
+    protected TitleBar createTitleBar(Context context, ReactViewCreator buttonCreator, TitleBarReactViewCreator reactViewCreator, TopBarButtonController.OnClickListener onClickListener) {
55
+        return new TitleBar(context,
56
+                buttonCreator,
57
+                new TitleBarReactViewController((Activity) context, reactViewCreator),
58
+                onClickListener
59
+        );
51 60
     }
52 61
 
53 62
     public void setTitle(String title) {
@@ -74,6 +83,10 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
74 83
         titleBar.setTitleTypeface(typeface);
75 84
     }
76 85
 
86
+    public void setComponent(String componentName, TitleOptions.Alignment alignment) {
87
+        titleBar.setComponent(componentName, alignment);
88
+    }
89
+
77 90
     public void setTopTabFontFamily(int tabIndex, Typeface fontFamily) {
78 91
         topTabs.setFontFamily(tabIndex, fontFamily);
79 92
     }

+ 0
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/TopBarButtonCreator.java 查看文件

@@ -3,7 +3,6 @@ package com.reactnativenavigation.views;
3 3
 import android.app.Activity;
4 4
 
5 5
 import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.react.TopBarReactButtonView;
7 6
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
8 7
 
9 8
 public class TopBarButtonCreator implements ReactViewCreator {

lib/android/app/src/main/java/com/reactnativenavigation/react/TopBarReactButtonView.java → lib/android/app/src/main/java/com/reactnativenavigation/views/TopBarReactButtonView.java 查看文件

@@ -1,9 +1,10 @@
1
-package com.reactnativenavigation.react;
1
+package com.reactnativenavigation.views;
2 2
 
3 3
 import android.annotation.SuppressLint;
4 4
 import android.content.Context;
5 5
 
6 6
 import com.facebook.react.ReactInstanceManager;
7
+import com.reactnativenavigation.react.ReactView;
7 8
 
8 9
 @SuppressLint("ViewConstructor")
9 10
 public class TopBarReactButtonView extends ReactView {

lib/android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java → lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java 查看文件

@@ -1,4 +1,4 @@
1
-package com.reactnativenavigation.views;
1
+package com.reactnativenavigation.views.titlebar;
2 2
 
3 3
 import android.annotation.SuppressLint;
4 4
 import android.app.Activity;
@@ -11,10 +11,12 @@ import android.view.View;
11 11
 import android.view.ViewGroup;
12 12
 import android.widget.TextView;
13 13
 
14
+import com.reactnativenavigation.parse.TitleOptions;
14 15
 import com.reactnativenavigation.parse.params.Button;
15 16
 import com.reactnativenavigation.parse.params.Color;
16 17
 import com.reactnativenavigation.parse.params.Fraction;
17 18
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
19
+import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
18 20
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
19 21
 
20 22
 import java.util.ArrayList;
@@ -23,13 +25,15 @@ import java.util.List;
23 25
 @SuppressLint("ViewConstructor")
24 26
 public class TitleBar extends Toolbar {
25 27
     private final ReactViewCreator buttonCreator;
28
+    private TitleBarReactViewController reactViewController;
26 29
     private final TopBarButtonController.OnClickListener onClickListener;
27 30
     private final List<TopBarButtonController> rightButtonControllers = new ArrayList<>();
28 31
     private TopBarButtonController leftButtonController;
29 32
 
30
-    public TitleBar(Context context, ReactViewCreator buttonCreator, TopBarButtonController.OnClickListener onClickListener) {
33
+    public TitleBar(Context context, ReactViewCreator buttonCreator, TitleBarReactViewController reactViewController, TopBarButtonController.OnClickListener onClickListener) {
31 34
         super(context);
32 35
         this.buttonCreator = buttonCreator;
36
+        this.reactViewController = reactViewController;
33 37
         this.onClickListener = onClickListener;
34 38
         getMenu();
35 39
         setContentDescription("titleBar");
@@ -39,29 +43,34 @@ public class TitleBar extends Toolbar {
39 43
         return super.getTitle() == null ? "" : (String) super.getTitle();
40 44
     }
41 45
 
42
-    void setTitleTextColor(Color color) {
46
+    public void setTitleTextColor(Color color) {
43 47
         if (color.hasValue()) setTitleTextColor(color.get());
44 48
     }
45 49
 
46
-    void setBackgroundColor(Color color) {
50
+    public void setComponent(String componentName, TitleOptions.Alignment alignment) {
51
+        reactViewController.setComponent(componentName, alignment);
52
+        addView(reactViewController.getView(), ViewGroup.LayoutParams.WRAP_CONTENT, getHeight());
53
+    }
54
+
55
+    public void setBackgroundColor(Color color) {
47 56
         if (color.hasValue()) setBackgroundColor(color.get());
48 57
     }
49 58
 
50
-    void setTitleFontSize(Fraction size) {
59
+    public void setTitleFontSize(Fraction size) {
51 60
         TextView titleTextView = getTitleTextView();
52 61
         if (titleTextView != null && size.hasValue()) {
53 62
             titleTextView.setTextSize(size.get());
54 63
         }
55 64
     }
56 65
 
57
-    void setTitleTypeface(Typeface typeface) {
66
+    public void setTitleTypeface(Typeface typeface) {
58 67
         TextView titleTextView = getTitleTextView();
59 68
         if (titleTextView != null) {
60 69
             titleTextView.setTypeface(typeface);
61 70
         }
62 71
     }
63 72
 
64
-    TextView getTitleTextView() {
73
+    public TextView getTitleTextView() {
65 74
         return findTextView(this);
66 75
     }
67 76
 

+ 15
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactView.java 查看文件

@@ -0,0 +1,15 @@
1
+package com.reactnativenavigation.views.titlebar;
2
+
3
+import android.annotation.SuppressLint;
4
+import android.content.Context;
5
+
6
+import com.facebook.react.ReactInstanceManager;
7
+import com.reactnativenavigation.react.ReactView;
8
+
9
+@SuppressLint("ViewConstructor")
10
+public class TitleBarReactView extends ReactView {
11
+
12
+    public TitleBarReactView(Context context, ReactInstanceManager reactInstanceManager, String componentId, String componentName) {
13
+        super(context, reactInstanceManager, componentId, componentName);
14
+    }
15
+}

+ 20
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBarReactViewCreator.java 查看文件

@@ -0,0 +1,20 @@
1
+package com.reactnativenavigation.views.titlebar;
2
+
3
+import android.app.Activity;
4
+
5
+import com.facebook.react.ReactInstanceManager;
6
+import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
7
+
8
+public class TitleBarReactViewCreator implements ReactViewCreator {
9
+
10
+    protected ReactInstanceManager instanceManager;
11
+
12
+    public TitleBarReactViewCreator(ReactInstanceManager instanceManager) {
13
+        this.instanceManager = instanceManager;
14
+	}
15
+
16
+	@Override
17
+	public TitleBarReactView create(Activity activity, String componentId, String componentName) {
18
+        return new TitleBarReactView(activity, instanceManager, componentId, componentName);
19
+    }
20
+}

+ 20
- 0
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java 查看文件

@@ -0,0 +1,20 @@
1
+package com.reactnativenavigation.mocks;
2
+
3
+import android.app.Activity;
4
+
5
+import com.facebook.react.ReactInstanceManager;
6
+import com.reactnativenavigation.views.titlebar.TitleBarReactView;
7
+import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
8
+
9
+import static org.mockito.Mockito.mock;
10
+
11
+public class TitleBarReactViewCreatorMock extends TitleBarReactViewCreator {
12
+    public TitleBarReactViewCreatorMock() {
13
+        super(mock(ReactInstanceManager.class));
14
+    }
15
+
16
+    @Override
17
+    public TitleBarReactView create(Activity activity, String componentId, String componentName) {
18
+        return new TitleBarReactView(activity, instanceManager, componentId, componentName);
19
+    }
20
+}

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TopBarButtonCreatorMock.java 查看文件

@@ -3,7 +3,7 @@ package com.reactnativenavigation.mocks;
3 3
 import android.app.Activity;
4 4
 
5 5
 import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.react.TopBarReactButtonView;
6
+import com.reactnativenavigation.views.TopBarReactButtonView;
7 7
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
8 8
 
9 9
 import static org.mockito.Mockito.mock;

+ 31
- 21
lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java 查看文件

@@ -31,6 +31,7 @@ public class OptionsTest extends BaseTest {
31 31
     private static final int TOP_BAR_FONT_SIZE = 18;
32 32
     private static final String TOP_BAR_FONT_FAMILY = "HelveticaNeue-CondensedBold";
33 33
     private static final Typeface TOP_BAR_TYPEFACE = Typeface.create("HelveticaNeue-CondensedBold", Typeface.BOLD);
34
+    private static final String TITLE_ALIGNMENT = "center";
34 35
     private static final Bool TOP_BAR_VISIBLE = new Bool(true);
35 36
     private static final Bool TOP_BAR_DRAW_BEHIND = new Bool(true);
36 37
     private static final Bool TOP_BAR_HIDE_ON_SCROLL = new Bool(true);
@@ -63,11 +64,11 @@ public class OptionsTest extends BaseTest {
63 64
     }
64 65
 
65 66
     private void assertResult(Options result) {
66
-        assertThat(result.topBarOptions.title.get()).isEqualTo(TITLE);
67
-        assertThat(result.topBarOptions.backgroundColor.get()).isEqualTo(TOP_BAR_BACKGROUND_COLOR);
68
-        assertThat(result.topBarOptions.textColor.get()).isEqualTo(TOP_BAR_TEXT_COLOR);
69
-        assertThat(result.topBarOptions.textFontSize.get()).isEqualTo(TOP_BAR_FONT_SIZE);
70
-        assertThat(result.topBarOptions.textFontFamily).isEqualTo(TOP_BAR_TYPEFACE);
67
+        assertThat(result.topBarOptions.title.text.get()).isEqualTo(TITLE);
68
+        assertThat(result.topBarOptions.background.color.get()).isEqualTo(TOP_BAR_BACKGROUND_COLOR);
69
+        assertThat(result.topBarOptions.title.color.get()).isEqualTo(TOP_BAR_TEXT_COLOR);
70
+        assertThat(result.topBarOptions.title.fontSize.get()).isEqualTo(TOP_BAR_FONT_SIZE);
71
+        assertThat(result.topBarOptions.title.fontFamily).isEqualTo(TOP_BAR_TYPEFACE);
71 72
         assertThat(result.topBarOptions.visible.get()).isEqualTo(TOP_BAR_VISIBLE.get());
72 73
         assertThat(result.topBarOptions.drawBehind.get()).isEqualTo(TOP_BAR_DRAW_BEHIND.get());
73 74
         assertThat(result.topBarOptions.hideOnScroll.get()).isEqualTo(TOP_BAR_HIDE_ON_SCROLL.get());
@@ -83,6 +84,7 @@ public class OptionsTest extends BaseTest {
83 84
         assertThat(result.fabOptions.hideOnScroll.get()).isEqualTo(FAB_HIDE_ON_SCROLL);
84 85
         assertThat(result.fabOptions.alignVertically.get()).isEqualTo(FAB_ALIGN_VERTICALLY);
85 86
         assertThat(result.fabOptions.alignHorizontally.get()).isEqualTo(FAB_ALIGN_HORIZONTALLY);
87
+        assertThat(result.topBarOptions.title.alignment).isEqualTo(TitleOptions.Alignment.Center);
86 88
     }
87 89
 
88 90
     @NonNull
@@ -97,16 +99,27 @@ public class OptionsTest extends BaseTest {
97 99
     @NonNull
98 100
     private JSONObject createTopBar(boolean visible) throws JSONException {
99 101
         return new JSONObject()
100
-                .put("title", "the title")
101
-                .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
102
-                .put("textColor", TOP_BAR_TEXT_COLOR)
103
-                .put("textFontSize", TOP_BAR_FONT_SIZE)
104
-                .put("textFontFamily", TOP_BAR_FONT_FAMILY)
102
+                .put("title", createTitle())
103
+                .put("background", createBackground())
105 104
                 .put("visible", visible)
106 105
                 .put("drawBehind", TOP_BAR_DRAW_BEHIND.get())
107 106
                 .put("hideOnScroll", TOP_BAR_HIDE_ON_SCROLL.get());
108 107
     }
109 108
 
109
+    private JSONObject createBackground() throws JSONException {
110
+        return new JSONObject()
111
+                .put("color", TOP_BAR_BACKGROUND_COLOR);
112
+    }
113
+
114
+    private JSONObject createTitle() throws JSONException {
115
+        return new JSONObject()
116
+                .put("text", "the title")
117
+                .put("color", TOP_BAR_TEXT_COLOR)
118
+                .put("fontSize", TOP_BAR_FONT_SIZE)
119
+                .put("fontFamily", TOP_BAR_FONT_FAMILY)
120
+                .put("alignment", TITLE_ALIGNMENT);
121
+    }
122
+
110 123
     @NonNull
111 124
     private JSONObject createFab() throws JSONException {
112 125
         return new JSONObject()
@@ -136,11 +149,8 @@ public class OptionsTest extends BaseTest {
136 149
     @NonNull
137 150
     private JSONObject createOtherTopBar() throws JSONException {
138 151
         return new JSONObject()
139
-                .put("title", "the title")
140
-                .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
141
-                .put("textColor", TOP_BAR_TEXT_COLOR)
142
-                .put("textFontSize", TOP_BAR_FONT_SIZE)
143
-                .put("textFontFamily", TOP_BAR_FONT_FAMILY)
152
+                .put("title", createTitle())
153
+                .put("background", createBackground())
144 154
                 .put("visible", TOP_BAR_VISIBLE);
145 155
     }
146 156
 
@@ -159,17 +169,17 @@ public class OptionsTest extends BaseTest {
159 169
         JSONObject json1 = new JSONObject();
160 170
         json1.put("topBar", createTopBar(true));
161 171
         Options options1 = Options.parse(mockLoader, json1);
162
-        options1.topBarOptions.title = new Text("some title");
172
+        options1.topBarOptions.title.text = new Text("some title");
163 173
 
164 174
         JSONObject json2 = new JSONObject();
165 175
         json2.put("topBar", createTopBar(false));
166 176
         Options options2 = Options.parse(mockLoader, json2);
167
-        options2.topBarOptions.title = new NullText();
177
+        options2.topBarOptions.title.text = new NullText();
168 178
 
169 179
         Options merged = options1.mergeWith(options2);
170 180
         assertThat(options1.topBarOptions.visible.get()).isTrue();
171 181
         assertThat(merged.topBarOptions.visible.get()).isFalse();
172
-        assertThat(merged.topBarOptions.title.get()).isEqualTo("some title");
182
+        assertThat(merged.topBarOptions.title.text.get()).isEqualTo("some title");
173 183
     }
174 184
 
175 185
     @Test
@@ -203,7 +213,7 @@ public class OptionsTest extends BaseTest {
203 213
     @Test
204 214
     public void defaultEmptyOptions() throws Exception {
205 215
         Options uut = new Options();
206
-        assertThat(uut.topBarOptions.title.get("")).isEmpty();
216
+        assertThat(uut.topBarOptions.title.text.get("")).isEmpty();
207 217
     }
208 218
 
209 219
     @Test
@@ -216,9 +226,9 @@ public class OptionsTest extends BaseTest {
216 226
     @Test
217 227
     public void clear_topBarOptions() throws Exception {
218 228
         Options uut = new Options();
219
-        uut.topBarOptions.title = new Text("some title");
229
+        uut.topBarOptions.title.text = new Text("some title");
220 230
         uut.clearTopBarOptions();
221
-        assertThat(uut.topBarOptions.title.hasValue()).isFalse();
231
+        assertThat(uut.topBarOptions.title.text.hasValue()).isFalse();
222 232
     }
223 233
 
224 234
     @Test

+ 7
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java 查看文件

@@ -8,6 +8,7 @@ import com.reactnativenavigation.BaseTest;
8 8
 import com.reactnativenavigation.mocks.ImageLoaderMock;
9 9
 import com.reactnativenavigation.mocks.MockPromise;
10 10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11 12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12 13
 import com.reactnativenavigation.parse.Options;
13 14
 import com.reactnativenavigation.parse.params.Color;
@@ -100,7 +101,7 @@ public class BottomTabsControllerTest extends BaseTest {
100 101
     public void findControllerById_ReturnsSelfOrChildren() throws Exception {
101 102
         assertThat(uut.findControllerById("123")).isNull();
102 103
         assertThat(uut.findControllerById(uut.getId())).isEqualTo(uut);
103
-        StackController inner = new StackController(activity, new TopBarButtonCreatorMock(), "inner", tabOptions);
104
+        StackController inner = createStack("inner");
104 105
         inner.animatePush(child1, new MockPromise());
105 106
         assertThat(uut.findControllerById(child1.getId())).isNull();
106 107
         uut.setTabs(Collections.singletonList(inner));
@@ -131,7 +132,7 @@ public class BottomTabsControllerTest extends BaseTest {
131 132
         uut.setTabs(tabs);
132 133
         uut.ensureViewIsCreated();
133 134
 
134
-        StackController stack = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
135
+        StackController stack = spy(createStack("stack"));
135 136
         stack.ensureViewIsCreated();
136 137
         stack.push(uut, new MockPromise());
137 138
 
@@ -169,4 +170,8 @@ public class BottomTabsControllerTest extends BaseTest {
169 170
     private List<ViewController> createTabs() {
170 171
         return Arrays.asList(child1, child2, child3, child4, child5);
171 172
     }
173
+
174
+    private StackController createStack(String id) {
175
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, tabOptions);
176
+    }
172 177
 }

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java 查看文件

@@ -5,6 +5,7 @@ import android.app.Activity;
5 5
 import com.reactnativenavigation.BaseTest;
6 6
 import com.reactnativenavigation.mocks.TestComponentLayout;
7 7
 import com.reactnativenavigation.mocks.TestReactView;
8
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
8 9
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9 10
 import com.reactnativenavigation.parse.Options;
10 11
 import com.reactnativenavigation.views.StackLayout;
@@ -26,7 +27,7 @@ public class ComponentViewControllerTest extends BaseTest {
26 27
         super.beforeEach();
27 28
         Activity activity = newActivity();
28 29
         view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
29
-        ParentController<StackLayout> parentController = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
30
+        ParentController<StackLayout> parentController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
30 31
         uut = new ComponentViewController(activity, "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options());
31 32
         uut.setParentController(parentController);
32 33
         parentController.ensureViewIsCreated();

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/FloatingActionButtonTest.java 查看文件

@@ -8,6 +8,7 @@ import android.view.ViewGroup;
8 8
 import com.reactnativenavigation.BaseTest;
9 9
 import com.reactnativenavigation.mocks.MockPromise;
10 10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11 12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12 13
 import com.reactnativenavigation.parse.FabOptions;
13 14
 import com.reactnativenavigation.parse.Options;
@@ -33,7 +34,7 @@ public class FloatingActionButtonTest extends BaseTest {
33 34
     public void beforeEach() {
34 35
         super.beforeEach();
35 36
         activity = newActivity();
36
-        stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stackController", new Options());
37
+        stackController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stackController", new Options());
37 38
         Options options = getOptionsWithFab();
38 39
         childFab = new SimpleViewController(activity, "child1", options);
39 40
         childNoFab = new SimpleViewController(activity, "child2", new Options());

+ 7
- 6
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java 查看文件

@@ -8,6 +8,7 @@ import com.reactnativenavigation.mocks.ImageLoaderMock;
8 8
 import com.reactnativenavigation.mocks.MockPromise;
9 9
 import com.reactnativenavigation.mocks.SimpleComponentViewController;
10 10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11 12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12 13
 import com.reactnativenavigation.parse.Options;
13 14
 import com.reactnativenavigation.parse.params.Text;
@@ -46,7 +47,7 @@ public class NavigatorTest extends BaseTest {
46 47
         imageLoaderMock = ImageLoaderMock.mock();
47 48
         activity = newActivity();
48 49
         uut = new Navigator(activity);
49
-        parentController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
50
+        parentController = spy(newStack());
50 51
         parentController.ensureViewIsCreated();
51 52
         child1 = new SimpleViewController(activity, "child1", tabOptions);
52 53
         child2 = new SimpleViewController(activity, "child2", tabOptions);
@@ -226,14 +227,14 @@ public class NavigatorTest extends BaseTest {
226 227
     public void setOptions_CallsApplyNavigationOptions() {
227 228
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
228 229
         componentVc.setParentController(parentController);
229
-        assertThat(componentVc.options.topBarOptions.title.get("")).isEmpty();
230
+        assertThat(componentVc.options.topBarOptions.title.text.get("")).isEmpty();
230 231
         uut.setRoot(componentVc, new MockPromise());
231 232
 
232 233
         Options options = new Options();
233
-        options.topBarOptions.title = new Text("new title");
234
+        options.topBarOptions.title.text = new Text("new title");
234 235
 
235 236
         uut.setOptions("theId", options);
236
-        assertThat(componentVc.options.topBarOptions.title.get()).isEqualTo("new title");
237
+        assertThat(componentVc.options.topBarOptions.title.text.get()).isEqualTo("new title");
237 238
     }
238 239
 
239 240
     @Test
@@ -248,7 +249,7 @@ public class NavigatorTest extends BaseTest {
248 249
 
249 250
     @NonNull
250 251
     private StackController newStack() {
251
-        return new StackController(activity, new TopBarButtonCreatorMock(), "stack" + CompatUtils.generateViewId(), tabOptions);
252
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack" + CompatUtils.generateViewId(), tabOptions);
252 253
     }
253 254
 
254 255
     @Test
@@ -325,7 +326,7 @@ public class NavigatorTest extends BaseTest {
325 326
 
326 327
     @Test
327 328
     public void pushedStackCanBePopped() throws Exception {
328
-        StackController parent = new StackController(activity, new TopBarButtonCreatorMock(), "someStack", new Options());
329
+        StackController parent = newStack();
329 330
         parent.ensureViewIsCreated();
330 331
         uut.setRoot(parent, new MockPromise());
331 332
         parent.push(parentController, new MockPromise());

+ 16
- 15
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java 查看文件

@@ -10,6 +10,7 @@ import com.reactnativenavigation.BaseTest;
10 10
 import com.reactnativenavigation.mocks.MockPromise;
11 11
 import com.reactnativenavigation.mocks.TestComponentLayout;
12 12
 import com.reactnativenavigation.mocks.TestReactView;
13
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
13 14
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
14 15
 import com.reactnativenavigation.parse.Options;
15 16
 import com.reactnativenavigation.parse.params.Bool;
@@ -45,7 +46,7 @@ public class OptionsApplyingTest extends BaseTest {
45 46
                 (activity1, componentId, componentName) -> view,
46 47
                 initialNavigationOptions
47 48
         );
48
-        stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
49
+        stackController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
49 50
         stackController.ensureViewIsCreated();
50 51
         uut.setParentController(stackController);
51 52
     }
@@ -61,8 +62,8 @@ public class OptionsApplyingTest extends BaseTest {
61 62
 
62 63
     @Test
63 64
     public void initialOptionsAppliedOnAppear() throws Exception {
64
-        uut.options.topBarOptions.title = new Text("the title");
65
-        StackController stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stackId", new Options());
65
+        uut.options.topBarOptions.title.text = new Text("the title");
66
+        StackController stackController = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stackId", new Options());
66 67
         stackController.animatePush(uut, new MockPromise() {});
67 68
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
68 69
 
@@ -73,11 +74,11 @@ public class OptionsApplyingTest extends BaseTest {
73 74
     @Test
74 75
     public void mergeNavigationOptionsUpdatesCurrentOptions() throws Exception {
75 76
         uut.ensureViewIsCreated();
76
-        assertThat(uut.options.topBarOptions.title.get("")).isEmpty();
77
+        assertThat(uut.options.topBarOptions.title.text.get("")).isEmpty();
77 78
         Options options = new Options();
78
-        options.topBarOptions.title = new Text("new title");
79
+        options.topBarOptions.title.text = new Text("new title");
79 80
         uut.mergeOptions(options);
80
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo("new title");
81
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo("new title");
81 82
     }
82 83
 
83 84
     @Test
@@ -87,7 +88,7 @@ public class OptionsApplyingTest extends BaseTest {
87 88
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
88 89
 
89 90
         Options opts = new Options();
90
-        opts.topBarOptions.title = new Text("the new title");
91
+        opts.topBarOptions.title.text = new Text("the new title");
91 92
         uut.mergeOptions(opts);
92 93
 
93 94
         assertThat(stackController.getTopBar().getTitle()).isEqualTo("the new title");
@@ -99,7 +100,7 @@ public class OptionsApplyingTest extends BaseTest {
99 100
         uut.onViewAppeared();
100 101
 
101 102
         Options opts = new Options();
102
-        opts.topBarOptions.backgroundColor = new com.reactnativenavigation.parse.params.Color(Color.RED);
103
+        opts.topBarOptions.background.color = new com.reactnativenavigation.parse.params.Color(Color.RED);
103 104
         uut.mergeOptions(opts);
104 105
 
105 106
         assertThat(((ColorDrawable) stackController.getTopBar().getTitleBar().getBackground()).getColor()).isEqualTo(Color.RED);
@@ -112,8 +113,8 @@ public class OptionsApplyingTest extends BaseTest {
112 113
             @Override
113 114
             public void resolve(@Nullable Object value) {
114 115
                 Options opts = new Options();
115
-                opts.topBarOptions.title = new Text("the title");
116
-                opts.topBarOptions.textColor = new com.reactnativenavigation.parse.params.Color(Color.RED);
116
+                opts.topBarOptions.title.text = new Text("the title");
117
+                opts.topBarOptions.title.color = new com.reactnativenavigation.parse.params.Color(Color.RED);
117 118
                 uut.mergeOptions(opts);
118 119
 
119 120
                 assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
@@ -125,13 +126,13 @@ public class OptionsApplyingTest extends BaseTest {
125 126
     @Test
126 127
     public void appliesTopBarTextSize() throws Exception {
127 128
         assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
128
-        initialNavigationOptions.topBarOptions.title = new Text("the title");
129
+        initialNavigationOptions.topBarOptions.title.text = new Text("the title");
129 130
         uut.ensureViewIsCreated();
130 131
         uut.onViewAppeared();
131 132
 
132 133
         Options opts = new Options();
133
-        opts.topBarOptions.title = new Text("the title");
134
-        opts.topBarOptions.textFontSize = new Fraction(18);
134
+        opts.topBarOptions.title.text = new Text("the title");
135
+        opts.topBarOptions.title.fontSize = new Fraction(18);
135 136
         uut.mergeOptions(opts);
136 137
 
137 138
         assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
@@ -141,7 +142,7 @@ public class OptionsApplyingTest extends BaseTest {
141 142
     @Test
142 143
     public void appliesTopBarVisible() throws Exception {
143 144
         assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
144
-        initialNavigationOptions.topBarOptions.title = new Text("the title");
145
+        initialNavigationOptions.topBarOptions.title.text = new Text("the title");
145 146
         uut.ensureViewIsCreated();
146 147
         uut.onViewAppeared();
147 148
         assertThat(stackController.getTopBar().getVisibility()).isNotEqualTo(View.GONE);
@@ -156,7 +157,7 @@ public class OptionsApplyingTest extends BaseTest {
156 157
 
157 158
     @Test
158 159
     public void appliesDrawUnder() throws Exception {
159
-        uut.options.topBarOptions.title = new Text("the title");
160
+        uut.options.topBarOptions.title.text = new Text("the title");
160 161
         uut.options.topBarOptions.drawBehind = new Bool(false);
161 162
         uut.ensureViewIsCreated();
162 163
         stackController.animatePush(uut, new MockPromise() {

+ 12
- 7
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java 查看文件

@@ -8,6 +8,7 @@ import android.widget.FrameLayout;
8 8
 import com.reactnativenavigation.BaseTest;
9 9
 import com.reactnativenavigation.mocks.MockPromise;
10 10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11 12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12 13
 import com.reactnativenavigation.parse.Options;
13 14
 import com.reactnativenavigation.parse.params.Text;
@@ -38,7 +39,7 @@ public class ParentControllerTest extends BaseTest {
38 39
         activity = newActivity();
39 40
         children = new ArrayList<>();
40 41
         Options initialOptions = new Options();
41
-        initialOptions.topBarOptions.title = new Text(INITIAL_TITLE);
42
+        initialOptions.topBarOptions.title.text = new Text(INITIAL_TITLE);
42 43
         uut = spy(new ParentController(activity, "uut", initialOptions) {
43 44
 
44 45
             @NonNull
@@ -88,7 +89,7 @@ public class ParentControllerTest extends BaseTest {
88 89
 
89 90
     @Test
90 91
     public void findControllerById_Recursive() throws Exception {
91
-        StackController stackController = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
92
+        StackController stackController = createStack();
92 93
         SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
93 94
         SimpleViewController child2 = new SimpleViewController(activity, "child2", new Options());
94 95
         stackController.animatePush(child1, new MockPromise());
@@ -110,7 +111,7 @@ public class ParentControllerTest extends BaseTest {
110 111
 
111 112
     @Test
112 113
     public void optionsAreClearedWhenChildIsAppeared() throws Exception {
113
-        StackController stackController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
114
+        StackController stackController = spy(createStack());
114 115
         SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
115 116
         stackController.animatePush(child1, new MockPromise());
116 117
 
@@ -121,7 +122,7 @@ public class ParentControllerTest extends BaseTest {
121 122
     @Test
122 123
     public void mergeOptions_optionsAreMergedWhenChildAppears() throws Exception {
123 124
         Options options = new Options();
124
-        options.topBarOptions.title = new Text("new title");
125
+        options.topBarOptions.title.text = new Text("new title");
125 126
         ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
126 127
         children.add(child1);
127 128
         uut.ensureViewIsCreated();
@@ -132,14 +133,14 @@ public class ParentControllerTest extends BaseTest {
132 133
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
133 134
         verify(uut, times(1)).clearOptions();
134 135
         verify(uut, times(1)).applyOptions(optionsCaptor.capture(), viewCaptor.capture());
135
-        assertThat(optionsCaptor.getValue().topBarOptions.title.get()).isEqualTo("new title");
136
+        assertThat(optionsCaptor.getValue().topBarOptions.title.text.get()).isEqualTo("new title");
136 137
         assertThat(viewCaptor.getValue()).isEqualTo(child1.getView());
137 138
     }
138 139
 
139 140
     @Test
140 141
     public void mergeOptions_initialParentOptionsAreNotMutatedWhenChildAppears() throws Exception {
141 142
         Options options = new Options();
142
-        options.topBarOptions.title = new Text("new title");
143
+        options.topBarOptions.title.text = new Text("new title");
143 144
         ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
144 145
         children.add(child1);
145 146
 
@@ -147,6 +148,10 @@ public class ParentControllerTest extends BaseTest {
147 148
 
148 149
         child1.ensureViewIsCreated();
149 150
         child1.onViewAppeared();
150
-        assertThat(uut.initialOptions.topBarOptions.title.get()).isEqualTo(INITIAL_TITLE);
151
+        assertThat(uut.initialOptions.topBarOptions.title.text.get()).isEqualTo(INITIAL_TITLE);
152
+    }
153
+
154
+    private StackController createStack() {
155
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
151 156
     }
152 157
 }

+ 13
- 8
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java 查看文件

@@ -7,6 +7,7 @@ import android.view.View;
7 7
 import com.reactnativenavigation.BaseTest;
8 8
 import com.reactnativenavigation.mocks.MockPromise;
9 9
 import com.reactnativenavigation.mocks.SimpleViewController;
10
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
10 11
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
11 12
 import com.reactnativenavigation.parse.Options;
12 13
 import com.reactnativenavigation.parse.params.Bool;
@@ -39,7 +40,7 @@ public class StackControllerTest extends BaseTest {
39 40
     public void beforeEach() {
40 41
         super.beforeEach();
41 42
         activity = newActivity();
42
-        uut = new StackController(activity, new TopBarButtonCreatorMock(), "uut", new Options());
43
+        uut = createStackController("uut");
43 44
         child1 = spy(new SimpleViewController(activity, "child1", new Options()));
44 45
         child2 = spy(new SimpleViewController(activity, "child2", new Options()));
45 46
         child3 = spy(new SimpleViewController(activity, "child3", new Options()));
@@ -95,7 +96,7 @@ public class StackControllerTest extends BaseTest {
95 96
     @Test
96 97
     public void pop_layoutHandlesChildWillDisappear() throws Exception {
97 98
         final StackLayout[] stackLayout = new StackLayout[1];
98
-        uut = new StackController(activity, new TopBarButtonCreatorMock(), "uut", new Options()) {
99
+        uut = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "uut", new Options()) {
99 100
             @NonNull
100 101
             @Override
101 102
             protected StackLayout createView() {
@@ -134,7 +135,7 @@ public class StackControllerTest extends BaseTest {
134 135
         uut.animatePush(child1, new MockPromise());
135 136
         assertThat(child1.getParentController()).isEqualTo(uut);
136 137
 
137
-        StackController anotherNavController = new StackController(activity, new TopBarButtonCreatorMock(), "another", new Options());
138
+        StackController anotherNavController = createStackController("another");
138 139
         anotherNavController.animatePush(child2, new MockPromise());
139 140
         assertThat(child2.getParentController()).isEqualTo(anotherNavController);
140 141
     }
@@ -314,7 +315,7 @@ public class StackControllerTest extends BaseTest {
314 315
 
315 316
     @Test
316 317
     public void findControllerById_Deeply() throws Exception {
317
-        StackController stack = new StackController(activity, new TopBarButtonCreatorMock(), "stack2", new Options());
318
+        StackController stack = createStackController("stack2");
318 319
         stack.animatePush(child2, new MockPromise());
319 320
         uut.animatePush(stack, new MockPromise());
320 321
         assertThat(uut.findControllerById(child2.getId())).isEqualTo(child2);
@@ -409,7 +410,7 @@ public class StackControllerTest extends BaseTest {
409 410
 
410 411
     @Test
411 412
     public void stackCanBePushed() throws Exception {
412
-        StackController parent = new StackController(activity, new TopBarButtonCreatorMock(), "someStack", new Options());
413
+        StackController parent = createStackController("someStack");
413 414
         parent.ensureViewIsCreated();
414 415
         parent.push(uut, new MockPromise());
415 416
         uut.onViewAppeared();
@@ -418,12 +419,12 @@ public class StackControllerTest extends BaseTest {
418 419
 
419 420
     @Test
420 421
     public void applyOptions_applyOnlyOnFirstStack() throws Exception {
421
-        StackController parent = spy(new StackController(activity, new TopBarButtonCreatorMock(), "someStack", new Options()));
422
+        StackController parent = spy(createStackController("someStack"));
422 423
         parent.ensureViewIsCreated();
423 424
         parent.push(uut, new MockPromise());
424 425
 
425 426
         Options childOptions = new Options();
426
-        childOptions.topBarOptions.title = new Text("Something");
427
+        childOptions.topBarOptions.title.text = new Text("Something");
427 428
         child1.options = childOptions;
428 429
         uut.push(child1, new MockPromise());
429 430
         child1.ensureViewIsCreated();
@@ -432,7 +433,7 @@ public class StackControllerTest extends BaseTest {
432 433
         ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
433 434
         ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
434 435
         verify(parent, times(1)).applyOptions(optionsCaptor.capture(), viewCaptor.capture());
435
-        assertThat(optionsCaptor.getValue().topBarOptions.title.hasValue()).isFalse();
436
+        assertThat(optionsCaptor.getValue().topBarOptions.title.text.hasValue()).isFalse();
436 437
     }
437 438
 
438 439
     @Test
@@ -456,4 +457,8 @@ public class StackControllerTest extends BaseTest {
456 457
         assertThat(uut.size()).isEqualTo(ids.length);
457 458
         assertThat(uut.getChildControllers()).extracting((Extractor<ViewController, String>) ViewController::getId).containsOnly(ids);
458 459
     }
460
+
461
+    private StackController createStackController(String id) {
462
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, new Options());
463
+    }
459 464
 }

+ 16
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java 查看文件

@@ -1,13 +1,17 @@
1 1
 package com.reactnativenavigation.viewcontrollers;
2 2
 
3 3
 import android.app.Activity;
4
+import android.view.ViewGroup;
4 5
 
5 6
 import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
6 8
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9
+import com.reactnativenavigation.parse.TitleOptions;
7 10
 import com.reactnativenavigation.parse.params.Button;
8 11
 import com.reactnativenavigation.parse.params.Text;
9 12
 import com.reactnativenavigation.react.ReactView;
10
-import com.reactnativenavigation.views.TitleBar;
13
+import com.reactnativenavigation.views.titlebar.TitleBar;
14
+import com.reactnativenavigation.views.titlebar.TitleBarReactView;
11 15
 
12 16
 import org.junit.Test;
13 17
 
@@ -19,6 +23,8 @@ import java.util.List;
19 23
 import java.util.Map;
20 24
 
21 25
 import static org.assertj.core.api.Java6Assertions.assertThat;
26
+import static org.mockito.ArgumentMatchers.any;
27
+import static org.mockito.ArgumentMatchers.eq;
22 28
 import static org.mockito.Mockito.spy;
23 29
 import static org.mockito.Mockito.times;
24 30
 import static org.mockito.Mockito.verify;
@@ -35,9 +41,10 @@ public class TitleBarTest extends BaseTest {
35 41
     public void beforeEach() {
36 42
         final TopBarButtonCreatorMock buttonCreator = new TopBarButtonCreatorMock();
37 43
         final Activity activity = newActivity();
44
+        TitleBarReactViewController reactViewController = new TitleBarReactViewController(activity, new TitleBarReactViewCreatorMock());
38 45
         createButtons();
39 46
         buttonControllers = new HashMap<>();
40
-        uut = spy(new TitleBar(activity, buttonCreator, (buttonId -> {})) {
47
+        uut = spy(new TitleBar(activity, buttonCreator, reactViewController, (buttonId -> {})) {
41 48
             @Override
42 49
             public TopBarButtonController createButtonController(Button button) {
43 50
                 TopBarButtonController controller = spy(super.createButtonController(button));
@@ -120,6 +127,13 @@ public class TitleBarTest extends BaseTest {
120 127
         assertThat(uut.getMenu().getItem(1).getTitle()).isEqualTo(textButton.title.get());
121 128
     }
122 129
 
130
+    @Test
131
+    public void setComponent_addsComponentToTitleBar() {
132
+        uut.setComponent("com.rnn.CustomView", TitleOptions.Alignment.Center);
133
+        final int height = uut.getHeight();
134
+        verify(uut, times(1)).addView(any(TitleBarReactView.class), eq(ViewGroup.LayoutParams.WRAP_CONTENT), eq(height));
135
+    }
136
+
123 137
     private List<Button> leftButton(Button leftButton) {
124 138
         return Collections.singletonList(leftButton);
125 139
     }

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopBarButtonControllerTest.java 查看文件

@@ -4,6 +4,7 @@ import android.app.Activity;
4 4
 import android.support.annotation.NonNull;
5 5
 
6 6
 import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
7 8
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
8 9
 import com.reactnativenavigation.parse.Options;
9 10
 import com.reactnativenavigation.parse.params.Button;
@@ -28,7 +29,7 @@ public class TopBarButtonControllerTest extends BaseTest {
28 29
 
29 30
         TopBarButtonCreatorMock buttonCreatorMock = new TopBarButtonCreatorMock();
30 31
         uut = spy(new TopBarButtonController(activity, button, buttonCreatorMock, (buttonId) -> {}));
31
-        stackController = spy(new StackController(activity, buttonCreatorMock, "stack", new Options()));
32
+        stackController = spy(new StackController(activity, buttonCreatorMock, new TitleBarReactViewCreatorMock(), "stack", new Options()));
32 33
 
33 34
     }
34 35
 

+ 12
- 6
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java 查看文件

@@ -8,6 +8,7 @@ import com.reactnativenavigation.BaseTest;
8 8
 import com.reactnativenavigation.mocks.MockPromise;
9 9
 import com.reactnativenavigation.mocks.TestComponentViewCreator;
10 10
 import com.reactnativenavigation.mocks.TestReactView;
11
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
11 12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
12 13
 import com.reactnativenavigation.parse.Options;
13 14
 import com.reactnativenavigation.parse.params.Text;
@@ -60,18 +61,23 @@ public class TopTabsViewControllerTest extends BaseTest {
60 61
         uut = spy(new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options));
61 62
         tabControllers.forEach(viewController -> viewController.setParentController(uut));
62 63
 
63
-        parentController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stackId", new Options()));
64
+        parentController = spy(createStackController("stackId"));
64 65
         parentController.push(uut, new MockPromise());
65 66
         uut.setParentController(parentController);
66 67
     }
67 68
 
69
+    @NonNull
70
+    private StackController createStackController(String id) {
71
+        return new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), id, new Options());
72
+    }
73
+
68 74
     @NonNull
69 75
     private ArrayList<Options> createOptions() {
70 76
         ArrayList result = new ArrayList();
71 77
         for (int i = 0; i < SIZE; i++) {
72 78
             final Options options = new Options();
73 79
             options.topTabOptions.title = new Text("Tab " + i);
74
-            options.topBarOptions.title = new Text(createTabTopBarTitle(i));
80
+            options.topBarOptions.title.text = new Text(createTabTopBarTitle(i));
75 81
             result.add(options);
76 82
         }
77 83
         return result;
@@ -173,17 +179,17 @@ public class TopTabsViewControllerTest extends BaseTest {
173 179
         uut.onViewAppeared();
174 180
         ReactComponent currentTab = tabView(0);
175 181
         verify(uut, times(1)).applyOptions(any(Options.class), eq(currentTab));
176
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(0));
182
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo(createTabTopBarTitle(0));
177 183
 
178 184
         uut.switchToTab(1);
179 185
         currentTab = tabView(1);
180 186
         verify(uut, times(1)).applyOptions(any(Options.class), eq(currentTab));
181
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(1));
187
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo(createTabTopBarTitle(1));
182 188
 
183 189
         uut.switchToTab(0);
184 190
         currentTab = tabView(0);
185 191
         verify(uut, times(2)).applyOptions(any(Options.class), eq(currentTab));
186
-        assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(0));
192
+        assertThat(uut.options.topBarOptions.title.text.get()).isEqualTo(createTabTopBarTitle(0));
187 193
     }
188 194
 
189 195
     private TestReactView getActualTabView(int index) {
@@ -215,7 +221,7 @@ public class TopTabsViewControllerTest extends BaseTest {
215 221
     public void applyOptions_tabsAreRemovedAfterViewDisappears() throws Exception {
216 222
         parentController.getView().removeAllViews();
217 223
 
218
-        StackController stackController = spy(new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options()));
224
+        StackController stackController = spy(createStackController("stack"));
219 225
         ComponentViewController first = new ComponentViewController(
220 226
                 activity,
221 227
                 "firstScreen",

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java 查看文件

@@ -9,6 +9,7 @@ import android.widget.LinearLayout;
9 9
 import com.reactnativenavigation.BaseTest;
10 10
 import com.reactnativenavigation.mocks.MockPromise;
11 11
 import com.reactnativenavigation.mocks.SimpleViewController;
12
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
12 13
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13 14
 import com.reactnativenavigation.parse.Options;
14 15
 
@@ -66,7 +67,7 @@ public class ViewControllerTest extends BaseTest {
66 67
     @Test
67 68
     public void holdsAReferenceToStackControllerOrNull() throws Exception {
68 69
         assertThat(uut.getParentController()).isNull();
69
-        StackController nav = new StackController(activity, new TopBarButtonCreatorMock(), "stack", new Options());
70
+        StackController nav = new StackController(activity, new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), "stack", new Options());
70 71
         nav.animatePush(uut, new MockPromise());
71 72
         assertThat(uut.getParentController()).isEqualTo(nav);
72 73
     }

+ 3
- 2
lib/android/app/src/test/java/com/reactnativenavigation/views/TopBarTest.java 查看文件

@@ -5,6 +5,7 @@ import android.view.MenuItem;
5 5
 
6 6
 import com.reactnativenavigation.BaseTest;
7 7
 import com.reactnativenavigation.anim.TopBarAnimator;
8
+import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
8 9
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
9 10
 import com.reactnativenavigation.parse.params.Bool;
10 11
 import com.reactnativenavigation.parse.params.Button;
@@ -38,8 +39,8 @@ public class TopBarTest extends BaseTest {
38 39
                 Log.i("TopBarTest", "onPress: " + buttonId);
39 40
             }
40 41
         });
41
-        StackLayout parent = new StackLayout(newActivity(), new TopBarButtonCreatorMock(), this.onClickListener);
42
-        uut = new TopBar(newActivity(), new TopBarButtonCreatorMock(), this.onClickListener, parent);
42
+        StackLayout parent = new StackLayout(newActivity(), new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), this.onClickListener);
43
+        uut = new TopBar(newActivity(), new TopBarButtonCreatorMock(), new TitleBarReactViewCreatorMock(), this.onClickListener, parent);
43 44
         animator = spy(new TopBarAnimator(uut));
44 45
         uut.setAnimator(animator);
45 46
         leftButton = createLeftButton();

+ 5
- 2
lib/ios/RNNCustomTitleView.h 查看文件

@@ -1,7 +1,10 @@
1 1
 #import <UIKit/UIKit.h>
2
+#import <React/RCTRootView.h>
3
+#import <React/RCTRootViewDelegate.h>
2 4
 
3
-@interface RNNCustomTitleView : UIView
5
+@interface RNNCustomTitleView : UIView <RCTRootViewDelegate>
4 6
 
5
--(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment;
7
+- (instancetype)initWithFrame:(CGRect)frame subView:(RCTRootView*)subView alignment:(NSString*)alignment;
6 8
 
7 9
 @end
10
+

+ 41
- 33
lib/ios/RNNCustomTitleView.m 查看文件

@@ -1,47 +1,55 @@
1 1
 #import "RNNCustomTitleView.h"
2 2
 
3 3
 @interface RNNCustomTitleView ()
4
-@property (nonatomic, strong) UIView *subView;
5
-@property (nonatomic, strong) NSString *subViewAlign;
4
+
5
+@property (nonatomic, strong) RCTRootView *subView;
6
+@property (nonatomic, strong) NSString *alignment;
7
+
6 8
 @end
7 9
 
8 10
 @implementation RNNCustomTitleView
9 11
 
12
+- (instancetype)initWithFrame:(CGRect)frame subView:(RCTRootView*)subView alignment:(NSString*)alignment {
13
+	self = [super init];
14
+	
15
+	if (self) {
16
+		self.subView = subView;
17
+		self.alignment = alignment;
18
+		
19
+		self.backgroundColor = [UIColor clearColor];
20
+		self.subView.backgroundColor = [UIColor clearColor];
21
+		
22
+		if ([alignment isEqualToString:@"fill"]) {
23
+			self.frame = frame;
24
+			subView.sizeFlexibility = RCTRootViewSizeFlexibilityNone;
25
+		} else {
26
+			self.subView.delegate = self;
27
+			subView.sizeFlexibility = RCTRootViewSizeFlexibilityWidthAndHeight;
28
+		}
29
+		
30
+		[self addSubview:subView];
31
+	}
32
+	
33
+	return self;
34
+}
10 35
 
11
--(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment {
12
-    self = [super initWithFrame:frame];
13
-    
14
-    if (self) {
15
-        self.backgroundColor = [UIColor clearColor];
16
-        self.subView = subView;
17
-        self.subViewAlign = alignment;
18
-        
19
-        subView.frame = self.bounds;
20
-        [self addSubview:subView];
21
-    }
22
-    
23
-    return self;
36
+- (void)layoutSubviews {
37
+	[super layoutSubviews];
38
+	if ([self.alignment isEqualToString:@"fill"]) {
39
+		[self.subView setFrame:self.bounds];
40
+	}
24 41
 }
25 42
 
43
+- (NSString *)alignment {
44
+	return _alignment ? _alignment : @"center";
45
+}
26 46
 
27
--(void)layoutSubviews {
28
-    [super layoutSubviews];
29
-    
30
-    if ([self.subViewAlign isEqualToString:@"fill"]) {
31
-        self.subView.frame = self.bounds;
32
-    }
33
-    else {
34
-        
35
-        CGFloat superViewWidth = self.superview.frame.size.width;
36
-        CGFloat paddingLeftFromCenter = (superViewWidth/2) - self.frame.origin.x;
37
-        CGFloat paddingRightFromCenter = self.frame.size.width - paddingLeftFromCenter;;
38
-        CGRect reactViewFrame = self.subView.bounds;
39
-        CGFloat minPadding = MIN(paddingLeftFromCenter, paddingRightFromCenter);
40
-        
41
-        reactViewFrame.size.width = minPadding*2;
42
-        reactViewFrame.origin.x = paddingLeftFromCenter - minPadding;
43
-        self.subView.frame = reactViewFrame;
44
-    }
47
+- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView {
48
+	if ([self.alignment isEqualToString:@"center"]) {
49
+		[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.subView.intrinsicContentSize.width, self.subView.intrinsicContentSize.height)];
50
+		[self.subView setFrame:CGRectMake(0, 0, rootView.intrinsicContentSize.width, rootView.intrinsicContentSize.height)];
51
+	}
45 52
 }
46 53
 
47 54
 @end
55
+

+ 6
- 1
lib/ios/RNNOptions.m 查看文件

@@ -17,7 +17,12 @@
17 17
 -(void)mergeWith:(NSDictionary *)otherOptions {
18 18
 	for (id key in otherOptions) {
19 19
 		if ([self hasProperty:key]) {
20
-			[self setValue:[otherOptions objectForKey:key] forKey:key];
20
+			if ([[self valueForKey:key] isKindOfClass:[RNNOptions class]]) {
21
+				RNNOptions* options = [self valueForKey:key];
22
+				[options mergeWith:[otherOptions objectForKey:key]];
23
+			} else {
24
+				[self setValue:[otherOptions objectForKey:key] forKey:key];
25
+			}
21 26
 		}
22 27
 	}
23 28
 }

+ 17
- 6
lib/ios/RNNRootViewController.m 查看文件

@@ -44,8 +44,10 @@
44 44
 -(void)viewWillAppear:(BOOL)animated{
45 45
 	[super viewWillAppear:animated];
46 46
 	[self.options applyOn:self];
47
+	
47 48
 	[self setCustomNavigationTitleView];
48 49
 	[self setCustomNavigationBarView];
50
+	[self setCustomNavigationComponentBackground];
49 51
 }
50 52
 
51 53
 -(void)viewDidAppear:(BOOL)animated {
@@ -71,23 +73,32 @@
71 73
 }
72 74
 
73 75
 - (void)setCustomNavigationTitleView {
74
-	if (self.options.topBar.customTitleViewName) {
75
-		UIView *reactView = [_creator createRootView:self.options.topBar.customTitleViewName rootViewId:self.options.topBar.customTitleViewName];
76
+	if (self.options.topBar.title.component) {
77
+		RCTRootView *reactView = (RCTRootView*)[_creator createRootView:self.options.topBar.title.component rootViewId:self.options.topBar.title.component];
76 78
 		
77
-		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:nil];
79
+		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:self.options.topBar.title.componentAlignment];
78 80
 		self.navigationItem.titleView = titleView;
79 81
 	}
80 82
 }
81 83
 
82 84
 - (void)setCustomNavigationBarView {
83
-	if (self.options.topBar.customViewName) {
84
-		UIView *reactView = [_creator createRootView:self.options.topBar.customViewName rootViewId:@"navBar"];
85
+	if (self.options.topBar.componentName) {
86
+		RCTRootView *reactView = (RCTRootView*)[_creator createRootView:self.options.topBar.componentName rootViewId:@"navBar"];
85 87
 		
86
-		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:nil];
88
+		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:@"fill"];
87 89
 		[self.navigationController.navigationBar addSubview:titleView];
88 90
 	}
89 91
 }
90 92
 
93
+- (void)setCustomNavigationComponentBackground {
94
+	if (self.options.topBar.backgroundComponentName) {
95
+		RCTRootView *reactView = (RCTRootView*)[_creator createRootView:self.options.topBar.backgroundComponentName rootViewId:@"navBarBackground"];
96
+		
97
+		RNNCustomTitleView *titleView = [[RNNCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:@"fill"];
98
+		[self.navigationController.navigationBar insertSubview:titleView atIndex:1];
99
+	}
100
+}
101
+
91 102
 -(BOOL)isCustomTransitioned {
92 103
 	return self.options.customTransition.animations != nil;
93 104
 }

+ 13
- 0
lib/ios/RNNTitleOptions.h 查看文件

@@ -0,0 +1,13 @@
1
+#import "RNNOptions.h"
2
+
3
+@interface RNNTitleOptions : RNNOptions
4
+
5
+@property (nonatomic, strong) NSString* text;
6
+@property (nonatomic, strong) NSNumber* fontSize;
7
+@property (nonatomic, strong) NSNumber* color;
8
+@property (nonatomic, strong) NSString* fontFamily;
9
+@property (nonatomic, strong) NSString* component;
10
+@property (nonatomic, strong) NSString* componentAlignment;
11
+
12
+
13
+@end

+ 32
- 0
lib/ios/RNNTitleOptions.m 查看文件

@@ -0,0 +1,32 @@
1
+#import "RNNTitleOptions.h"
2
+
3
+@implementation RNNTitleOptions
4
+
5
+- (void)applyOn:(UIViewController *)viewController {
6
+	if (self.text) {
7
+		viewController.navigationItem.title = self.text;
8
+	}
9
+	
10
+	if (self.fontFamily || self.fontSize || self.color) {
11
+		NSMutableDictionary* navigationBarTitleTextAttributes = [NSMutableDictionary new];
12
+		if (self.color) {
13
+			navigationBarTitleTextAttributes[NSForegroundColorAttributeName] = [RCTConvert UIColor:[self valueForKey:@"color"]];
14
+		}
15
+		if (self.fontFamily){
16
+			if(self.fontSize) {
17
+				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.fontFamily size:[self.fontSize floatValue]];
18
+			} else {
19
+				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.fontFamily size:20];
20
+			}
21
+		} else if (self.fontSize) {
22
+			navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont systemFontOfSize:[self.fontSize floatValue]];
23
+		}
24
+		viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
25
+		if (@available(iOS 11.0, *)){
26
+			viewController.navigationController.navigationBar.largeTitleTextAttributes = navigationBarTitleTextAttributes;
27
+		}
28
+		
29
+	}
30
+}
31
+
32
+@end

+ 4
- 6
lib/ios/RNNTopBarOptions.h 查看文件

@@ -1,27 +1,25 @@
1 1
 #import "RNNOptions.h"
2
+#import "RNNTitleOptions.h"
2 3
 
3 4
 @interface RNNTopBarOptions : RNNOptions
4 5
 
5 6
 @property (nonatomic, strong) NSArray* leftButtons;
6 7
 @property (nonatomic, strong) NSArray* rightButtons;
7 8
 @property (nonatomic, strong) NSNumber* backgroundColor;
8
-@property (nonatomic, strong) NSNumber* textColor;
9
-@property (nonatomic, strong) NSString* title;
10
-@property (nonatomic, strong) NSString* textFontFamily;
11 9
 @property (nonatomic, strong) NSNumber* visible;
12 10
 @property (nonatomic, strong) NSNumber* hideOnScroll;
13 11
 @property (nonatomic, strong) NSNumber* buttonColor;
14 12
 @property (nonatomic, strong) NSNumber* translucent;
15 13
 @property (nonatomic, strong) NSNumber* transparent;
16 14
 @property (nonatomic, strong) NSNumber* drawBehind;
17
-@property (nonatomic, strong) NSNumber* textFontSize;
18 15
 @property (nonatomic, strong) NSNumber* noBorder;
19 16
 @property (nonatomic, strong) NSNumber* blur;
20 17
 @property (nonatomic, strong) NSNumber* animate;
21 18
 @property (nonatomic, strong) NSNumber* largeTitle;
22 19
 @property (nonatomic, strong) NSString* testID;
20
+@property (nonatomic, strong) RNNTitleOptions* title;
23 21
 
24
-@property (nonatomic, strong) NSString* customTitleViewName;
25
-@property (nonatomic, strong) NSString* customViewName;
22
+@property (nonatomic, strong) NSString* componentName;
23
+@property (nonatomic, strong) NSString* backgroundComponentName;
26 24
 
27 25
 @end

+ 9
- 25
lib/ios/RNNTopBarOptions.m 查看文件

@@ -13,18 +13,21 @@ extern const NSInteger BLUR_TOPBAR_TAG;
13 13
 
14 14
 @implementation RNNTopBarOptions
15 15
 
16
+- (instancetype)initWithDict:(NSDictionary *)dict {
17
+	self = [super initWithDict:dict];
18
+	self.title = [RNNTitleOptions new];
19
+	return self;
20
+}
21
+
16 22
 - (void)applyOn:(UIViewController*)viewController {
23
+	[self.title applyOn:viewController];
17 24
 	if (self.backgroundColor) {
18 25
 		UIColor* backgroundColor = [RCTConvert UIColor:self.backgroundColor];
19 26
 		viewController.navigationController.navigationBar.barTintColor = backgroundColor;
20 27
 	} else {
21 28
 		viewController.navigationController.navigationBar.barTintColor = nil;
22 29
 	}
23
-	
24
-	if (self.title) {
25
-		viewController.navigationItem.title = self.title;
26
-	}
27
-	
30
+
28 31
 	if (@available(iOS 11.0, *)) {
29 32
 		if (self.largeTitle){
30 33
 			if ([self.largeTitle boolValue]) {
@@ -40,26 +43,7 @@ extern const NSInteger BLUR_TOPBAR_TAG;
40 43
 	}
41 44
 	
42 45
 	
43
-	if (self.textFontFamily || self.textFontSize || self.textColor) {
44
-		NSMutableDictionary* navigationBarTitleTextAttributes = [NSMutableDictionary new];
45
-		if (self.textColor) {
46
-			navigationBarTitleTextAttributes[NSForegroundColorAttributeName] = [RCTConvert UIColor:[self valueForKey:@"textColor"]];
47
-		}
48
-		if (self.textFontFamily){
49
-			if(self.textFontSize) {
50
-				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.textFontFamily size:[self.textFontSize floatValue]];
51
-			} else {
52
-				navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont fontWithName:self.textFontFamily size:20];
53
-			}
54
-		} else if (self.textFontSize) {
55
-			navigationBarTitleTextAttributes[NSFontAttributeName] = [UIFont systemFontOfSize:[self.textFontSize floatValue]];
56
-		}
57
-		viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
58
-		if (@available(iOS 11.0, *)){
59
-			viewController.navigationController.navigationBar.largeTitleTextAttributes = navigationBarTitleTextAttributes;
60
-		}
61
-		
62
-	}
46
+	
63 47
 	
64 48
 	
65 49
 	if (self.visible) {

+ 8
- 0
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj 查看文件

@@ -81,6 +81,8 @@
81 81
 		504AFE751FFFF0540076E904 /* RNNTopTabsOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 504AFE731FFFF0540076E904 /* RNNTopTabsOptions.m */; };
82 82
 		504AFE761FFFF1E00076E904 /* RNNNavigationOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E83BAD691F27362500A9F3DD /* RNNNavigationOptions.h */; };
83 83
 		504AFE771FFFF1E20076E904 /* RNNTopBarOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */; };
84
+		50570B262061473D006A1B5C /* RNNTitleOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50570B242061473D006A1B5C /* RNNTitleOptions.h */; };
85
+		50570B272061473D006A1B5C /* RNNTitleOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50570B252061473D006A1B5C /* RNNTitleOptions.m */; };
84 86
 		50762D08205E96C200E3D18A /* RNNModalAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 50762D06205E96C200E3D18A /* RNNModalAnimation.h */; };
85 87
 		50762D09205E96C200E3D18A /* RNNModalAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 50762D07205E96C200E3D18A /* RNNModalAnimation.m */; };
86 88
 		507E7D57201DDD3000444E6C /* RNNAnimationOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 507E7D55201DDD3000444E6C /* RNNAnimationOptions.h */; };
@@ -268,6 +270,8 @@
268 270
 		504AFE631FFE53070076E904 /* RNNOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOptions.m; sourceTree = "<group>"; };
269 271
 		504AFE721FFFF0540076E904 /* RNNTopTabsOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTopTabsOptions.h; sourceTree = "<group>"; };
270 272
 		504AFE731FFFF0540076E904 /* RNNTopTabsOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTopTabsOptions.m; sourceTree = "<group>"; };
273
+		50570B242061473D006A1B5C /* RNNTitleOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTitleOptions.h; sourceTree = "<group>"; };
274
+		50570B252061473D006A1B5C /* RNNTitleOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTitleOptions.m; sourceTree = "<group>"; };
271 275
 		50762D06205E96C200E3D18A /* RNNModalAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNModalAnimation.h; sourceTree = "<group>"; };
272 276
 		50762D07205E96C200E3D18A /* RNNModalAnimation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNModalAnimation.m; sourceTree = "<group>"; };
273 277
 		507E7D55201DDD3000444E6C /* RNNAnimationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNAnimationOptions.h; sourceTree = "<group>"; };
@@ -485,6 +489,8 @@
485 489
 				E83BAD6A1F27363A00A9F3DD /* RNNNavigationOptions.m */,
486 490
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
487 491
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
492
+				50570B242061473D006A1B5C /* RNNTitleOptions.h */,
493
+				50570B252061473D006A1B5C /* RNNTitleOptions.m */,
488 494
 				A7626BFF1FC578AB00492FB8 /* RNNBottomTabsOptions.h */,
489 495
 				A7626C001FC5796200492FB8 /* RNNBottomTabsOptions.m */,
490 496
 				50EB933F1FE14A3E00BD8EEE /* RNNBottomTabOptions.h */,
@@ -768,6 +774,7 @@
768 774
 				263905B31E4C6F440023D7D3 /* MMDrawerVisualState.h in Headers */,
769 775
 				50451D092042E20600695F00 /* RNNTransitionsOptions.h in Headers */,
770 776
 				E8A5CD621F49114F00E89D0D /* RNNElement.h in Headers */,
777
+				50570B262061473D006A1B5C /* RNNTitleOptions.h in Headers */,
771 778
 				504AFE741FFFF0540076E904 /* RNNTopTabsOptions.h in Headers */,
772 779
 				E8E5182E1F83A48B000467AC /* RNNTransitionStateHolder.h in Headers */,
773 780
 				507E7D57201DDD3000444E6C /* RNNAnimationOptions.h in Headers */,
@@ -902,6 +909,7 @@
902 909
 				261F0E6B1E6F028A00989DE2 /* RNNNavigationStackManager.m in Sources */,
903 910
 				5016E8F020209690009D4F7C /* RNNCustomTitleView.m in Sources */,
904 911
 				E8DA24411F97459B00CD552B /* RNNElementFinder.m in Sources */,
912
+				50570B272061473D006A1B5C /* RNNTitleOptions.m in Sources */,
905 913
 				263905BF1E4C6F440023D7D3 /* RCCTheSideBarManagerViewController.m in Sources */,
906 914
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
907 915
 				A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */,

+ 1
- 1
lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m 查看文件

@@ -63,7 +63,7 @@
63 63
 
64 64
 -(void)testDynamicStylesMergeWithStaticStyles {
65 65
 	RNNNavigationOptions* initialOptions = [[RNNNavigationOptions alloc] init];
66
-	[initialOptions.topBar setTitle:@"the title"];
66
+	initialOptions.topBar.title.text = @"the title";
67 67
 	RNNRootViewController* vc = [[RNNRootViewController alloc] initWithName:@"name"
68 68
 																withOptions:initialOptions
69 69
 															withComponentId:@"componentId"

+ 2
- 2
lib/ios/ReactNativeNavigationTests/RNNNavigationOptionsTest.m 查看文件

@@ -22,9 +22,9 @@
22 22
 
23 23
 - (void)testChangeRNNNavigationOptionsDynamically {
24 24
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:@{@"topBar": @{@"backgroundColor" : @(0xff0000ff)}}];
25
-	NSDictionary* dynamicOptions = @{@"topBar": @{@"textColor" : @(0xffff00ff), @"title" : @"hello"}};
25
+	NSDictionary* dynamicOptions = @{@"topBar": @{@"textColor" : @(0xffff00ff), @"title" : @{@"text": @"hello"}}};
26 26
 	[options mergeWith:dynamicOptions];
27
-	XCTAssertTrue([options.topBar.title isEqual:@"hello"]);
27
+	XCTAssertTrue([options.topBar.title.text isEqual:@"hello"]);
28 28
 }
29 29
 
30 30
 - (void)testChangeRNNNavigationOptionsWithInvalidProperties {

+ 12
- 12
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m 查看文件

@@ -106,7 +106,7 @@
106 106
 
107 107
 -(void)testTitle_string{
108 108
 	NSString* title =@"some title";
109
-	self.options.topBar.title = title;
109
+	self.options.topBar.title.text = title;
110 110
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
111 111
 	
112 112
 	[self.uut viewWillAppear:false];
@@ -122,7 +122,7 @@
122 122
 
123 123
 -(void)testTopBarTextColor_validColor{
124 124
 	NSNumber* inputColor = @(0xFFFF0000);
125
-	self.options.topBar.textColor = inputColor;
125
+	self.options.topBar.title.color = inputColor;
126 126
 	__unused UINavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
127 127
 	[self.uut viewWillAppear:false];
128 128
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
@@ -156,7 +156,7 @@
156 156
 -(void)testTopBarTextFontFamily_validFont{
157 157
 	NSString* inputFont = @"HelveticaNeue";
158 158
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
159
-	self.options.topBar.textFontFamily = inputFont;
159
+	self.options.topBar.title.fontFamily = inputFont;
160 160
 	[self.uut viewWillAppear:false];
161 161
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:20];
162 162
 	XCTAssertTrue([self.uut.navigationController.navigationBar.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
@@ -227,7 +227,7 @@
227 227
 
228 228
 -(void)testTopBarTextFontSize_withoutTextFontFamily_withoutTextColor {
229 229
 	NSNumber* topBarTextFontSizeInput = @(15);
230
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
230
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
231 231
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
232 232
 	[self.uut viewWillAppear:false];
233 233
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
@@ -237,8 +237,8 @@
237 237
 -(void)testTopBarTextFontSize_withoutTextFontFamily_withTextColor {
238 238
 	NSNumber* topBarTextFontSizeInput = @(15);
239 239
 	NSNumber* inputColor = @(0xFFFF0000);
240
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
241
-	self.options.topBar.textColor = inputColor;
240
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
241
+	self.options.topBar.title.color = inputColor;
242 242
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
243 243
 	[self.uut viewWillAppear:false];
244 244
 	UIFont* expectedFont = [UIFont systemFontOfSize:15];
@@ -251,9 +251,9 @@
251 251
 	NSNumber* topBarTextFontSizeInput = @(15);
252 252
 	NSNumber* inputColor = @(0xFFFF0000);
253 253
 	NSString* inputFont = @"HelveticaNeue";
254
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
255
-	self.options.topBar.textColor = inputColor;
256
-	self.options.topBar.textFontFamily = inputFont;
254
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
255
+	self.options.topBar.title.color = inputColor;
256
+	self.options.topBar.title.fontFamily = inputFont;
257 257
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
258 258
 	[self.uut viewWillAppear:false];
259 259
 	UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
@@ -265,8 +265,8 @@
265 265
 -(void)testTopBarTextFontSize_withTextFontFamily_withoutTextColor {
266 266
 	NSNumber* topBarTextFontSizeInput = @(15);
267 267
 	NSString* inputFont = @"HelveticaNeue";
268
-	self.options.topBar.textFontSize = topBarTextFontSizeInput;
269
-	self.options.topBar.textFontFamily = inputFont;
268
+	self.options.topBar.title.fontSize = topBarTextFontSizeInput;
269
+	self.options.topBar.title.fontFamily = inputFont;
270 270
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
271 271
 	[self.uut viewWillAppear:false];
272 272
 	UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
@@ -277,7 +277,7 @@
277 277
 -(void)testTopBarTextFontFamily_invalidFont{
278 278
 	NSString* inputFont = @"HelveticaNeueeeee";
279 279
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
280
-	self.options.topBar.textFontFamily = inputFont;
280
+	self.options.topBar.title.fontFamily = inputFont;
281 281
 	//	XCTAssertThrows([self.uut viewWillAppear:false]);
282 282
 }
283 283
 

+ 4
- 2
lib/src/commands/LayoutTreeParser.test.ts 查看文件

@@ -124,7 +124,7 @@ describe('LayoutTreeParser', () => {
124 124
       expect(result.children[1].children[0].children[2].children[0].type).toEqual('TopTabs');
125 125
       expect(result.children[1].children[0].children[2].children[0].children[2].type).toEqual('TopTabs');
126 126
       expect(result.children[1].children[0].children[2].children[0].children[2].children[4].type).toEqual('Stack');
127
-      expect(result.children[1].children[0].children[2].children[0].children[2].data).toEqual({ options: { topBar: { title: 'Hello1' } } });
127
+      expect(result.children[1].children[0].children[2].children[0].children[2].data).toEqual({ options: { topBar: { title: { text: 'Hello1'} } } });
128 128
     });
129 129
   });
130 130
 
@@ -163,7 +163,9 @@ const passProps = {
163 163
 
164 164
 const options = {
165 165
   topBar: {
166
-    title: 'Hello1'
166
+    title: {
167
+      text: 'Hello1'
168
+    }
167 169
   }
168 170
 };
169 171
 

+ 3
- 1
playground/src/screens/BackHandlerModalScreen.js 查看文件

@@ -7,7 +7,9 @@ class BackHandlerModalScreen extends Component {
7 7
   static get options() {
8 8
     return {
9 9
       topBar: {
10
-        title: 'Back Handler'
10
+        title: {
11
+          text: 'Back Handler'
12
+        }
11 13
       }
12 14
     };
13 15
   }

+ 5
- 3
playground/src/screens/BackHandlerScreen.js 查看文件

@@ -7,9 +7,11 @@ class BackHandlerScreen extends Component {
7 7
   static get options() {
8 8
     return {
9 9
       topBar: {
10
-        title: 'Back Handler',
11
-        textColor: 'black',
12
-        textFontSize: 16
10
+        title: {
11
+          text: 'Back Handler',
12
+          color: 'black',
13
+          fontSize: 16
14
+        }
13 15
       }
14 16
     };
15 17
   }

+ 1
- 1
playground/src/screens/CustomTopBar.js 查看文件

@@ -42,6 +42,6 @@ const styles = StyleSheet.create({
42 42
   },
43 43
   text: {
44 44
     alignSelf: 'center',
45
-    color: Platform.OS === 'ios' ? 'black' : 'white'
45
+    color: 'black'
46 46
   }
47 47
 });

+ 4
- 2
playground/src/screens/CustomTransitionDestination.js 查看文件

@@ -14,8 +14,10 @@ class CustomTransitionDestination extends Component {
14 14
     return {
15 15
       backButtonTransition: 'custom',
16 16
       topBar: {
17
-        title: 'ye babyyyyyy',
18
-        textFontFamily: 'HelveticaNeue-Italic',
17
+        title: {
18
+          text: 'ye babyyyyyy',
19
+          fontFamily: 'HelveticaNeue-Italic'
20
+        },
19 21
         largeTitle: true
20 22
       }
21 23
     };

+ 4
- 2
playground/src/screens/CustomTransitionOrigin.js 查看文件

@@ -11,8 +11,10 @@ class CustomTransitionOrigin extends Component {
11 11
   static get options() {
12 12
     return {
13 13
       topBar: {
14
-        textFontFamily: 'HelveticaNeue-Italic',
15
-        textFontSize: 16,
14
+        title: {
15
+          fontFamily: 'HelveticaNeue-Italic',
16
+          fontSize: 16
17
+        },
16 18
         largeTitle: false,
17 19
         translucent: true
18 20
       }

+ 27
- 13
playground/src/screens/OptionsScreen.js 查看文件

@@ -17,16 +17,18 @@ class OptionsScreen extends Component {
17 17
   static get options() {
18 18
     return {
19 19
       topBar: {
20
-        title: 'Static Title',
21
-        textColor: 'black',
20
+        title: {
21
+          text: 'Static Title',
22
+          color: 'black',
23
+          fontSize: 16,
24
+          fontFamily: 'HelveticaNeue-Italic',
25
+          largeTitle: false,
26
+        },
22 27
         ...Platform.select({
23 28
           android: { drawBehind: true },
24 29
           ios: { drawBehind: false, }
25 30
         }),
26
-        largeTitle: false,
27 31
         visible: true,
28
-        textFontSize: 16,
29
-        textFontFamily: 'HelveticaNeue-Italic',
30 32
         testID: testIDs.TOP_BAR_ELEMENT,
31 33
         rightButtons: [
32 34
           {
@@ -105,12 +107,11 @@ class OptionsScreen extends Component {
105 107
         <Button title='Top Bar Opaque' onPress={this.onClickTopBarOpaque} />
106 108
         <Button title='scrollView Screen' testID={testIDs.SCROLLVIEW_SCREEN_BUTTON} onPress={this.onClickScrollViewScreen} />
107 109
         <Button title='Custom Transition' testID={testIDs.CUSTOM_TRANSITION_BUTTON} onPress={this.onClickCustomTranstition} />
108
-        {Platform.OS === 'android' ?
109
-          <Button title='Hide fab' testID={testIDs.HIDE_FAB} onPress={this.onClickFab} />
110
-          : null}
110
+        {Platform.OS === 'android' ? <Button title='Hide fab' testID={testIDs.HIDE_FAB} onPress={this.onClickFab} /> : null}
111 111
         <Button title='Show overlay' testID={testIDs.SHOW_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(true)} />
112 112
         <Button title='Show touch through overlay' testID={testIDs.SHOW_TOUCH_THROUGH_OVERLAY_BUTTON} onPress={() => this.onClickShowOverlay(false)} />
113 113
         <Button title='Push Default Options Screen' testID={testIDs.PUSH_DEFAULT_OPTIONS_BUTTON} onPress={this.onClickPushDefaultOptionsScreen} />
114
+        <Button title='Show TopBar react view' testID={testIDs.SHOW_TOPBAR_REACT_VIEW} onPress={this.onShowTopBarReactView} />
114 115
         <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
115 116
       </View>
116 117
     );
@@ -161,12 +162,14 @@ class OptionsScreen extends Component {
161 162
   onClickDynamicOptions() {
162 163
     Navigation.setOptions(this.props.componentId, {
163 164
       topBar: {
164
-        title: 'Dynamic Title',
165
-        textColor: '#00FFFF',
166
-        largeTitle: false,
165
+        title: {
166
+          text: 'Dynamic Title',
167
+          color: '#00FFFF',
168
+          largeTitle: false,
169
+          fontSize: 20,
170
+          fontFamily: 'HelveticaNeue-CondensedBold'
171
+        },
167 172
         buttonColor: 'red',
168
-        textFontSize: 20,
169
-        textFontFamily: 'HelveticaNeue-CondensedBold'
170 173
       }
171 174
     });
172 175
   }
@@ -256,6 +259,17 @@ class OptionsScreen extends Component {
256 259
       }
257 260
     });
258 261
   }
262
+
263
+  onShowTopBarReactView = () => {
264
+    Navigation.setOptions(this.props.componentId, {
265
+      topBar: {
266
+        title: {
267
+          component: 'navigation.playground.CustomTopBar',
268
+          alignment: 'fill'
269
+        }
270
+      }
271
+    });
272
+  }
259 273
 }
260 274
 
261 275
 const styles = {

+ 3
- 1
playground/src/screens/PushedScreen.js 查看文件

@@ -52,7 +52,9 @@ class PushedScreen extends Component {
52 52
         },
53 53
         options: {
54 54
           topBar: {
55
-            title: `Pushed ${this.getStackPosition() + 1}`
55
+            title: {
56
+              text: `Pushed ${this.getStackPosition() + 1}`
57
+            }
56 58
           }
57 59
         }
58 60
       }

+ 5
- 3
playground/src/screens/ScrollViewScreen.js 查看文件

@@ -12,10 +12,12 @@ class ScrollViewScreen extends Component {
12 12
   static get options() {
13 13
     return {
14 14
       topBar: {
15
-        title: 'Collapse',
15
+        title: {
16
+          text: 'Collapse',
17
+          color: 'black',
18
+          fontSize: 16
19
+        },
16 20
         drawBehind: true,
17
-        textColor: 'black',
18
-        textFontSize: 16,
19 21
         visible: true,
20 22
         testID: testIDs.TOP_BAR_ELEMENT
21 23
       },

+ 11
- 7
playground/src/screens/TopTabOptionsScreen.js 查看文件

@@ -8,9 +8,11 @@ class TopTabOptionsScreen extends PureComponent {
8 8
   static get options() {
9 9
     return {
10 10
       topBar: {
11
-        textColor: 'black',
12
-        textFontSize: 16,
13
-        textFontFamily: 'HelveticaNeue-Italic'
11
+        title: {
12
+          color: 'black',
13
+          fontSize: 16,
14
+          fontFamily: 'HelveticaNeue-Italic'
15
+        }
14 16
       }
15 17
     };
16 18
   }
@@ -33,12 +35,14 @@ class TopTabOptionsScreen extends PureComponent {
33 35
   onClickDynamicOptions() {
34 36
     Navigation.setOptions(this.props.componentId, {
35 37
       topBar: {
36
-        title: 'Dynamic Title',
37
-        textColor: '#00FFFF',
38
+        title: {
39
+          text: 'Dynamic Title',
40
+          color: '#00FFFF',
41
+          fontSize: 16,
42
+          fontFamily: 'HelveticaNeue-CondensedBold'
43
+        },
38 44
         largeTitle: false,
39 45
         buttonColor: 'red',
40
-        textFontSize: 20,
41
-        textFontFamily: 'HelveticaNeue-CondensedBold'
42 46
       }
43 47
     });
44 48
   }

+ 5
- 3
playground/src/screens/TopTabScreen.js 查看文件

@@ -8,9 +8,11 @@ class TopTabScreen extends PureComponent {
8 8
   static get options() {
9 9
     return {
10 10
       topBar: {
11
-        textColor: 'black',
12
-        textFontSize: 16,
13
-        textFontFamily: 'HelveticaNeue-Italic'
11
+        title: {
12
+          color: 'black',
13
+          fontSize: 16,
14
+          fontFamily: 'HelveticaNeue-Italic'
15
+        }
14 16
       },
15 17
       fab: {
16 18
         id: FAB,

+ 28
- 9
playground/src/screens/WelcomeScreen.js 查看文件

@@ -10,7 +10,10 @@ class WelcomeScreen extends Component {
10 10
   static get options() {
11 11
     return {
12 12
       topBar: {
13
-        largeTitle: false,
13
+        title: {
14
+          largeTitle: false,
15
+          title: 'My Screen'
16
+        },
14 17
         drawBehind: true,
15 18
         visible: false,
16 19
         animate: false
@@ -57,7 +60,9 @@ class WelcomeScreen extends Component {
57 60
                     options: {
58 61
                       topBar: {
59 62
                         visible: true,
60
-                        title: 'React Native Navigation!'
63
+                        title: {
64
+                          text: 'React Native Navigation!'
65
+                        }
61 66
                       }
62 67
                     }
63 68
                   }
@@ -216,7 +221,9 @@ class WelcomeScreen extends Component {
216 221
         name: 'navigation.playground.PushedScreen',
217 222
         options: {
218 223
           topBar: {
219
-            title: 'pushed'
224
+            title: {
225
+              text: 'pushed'
226
+            }
220 227
           }
221 228
         }
222 229
       }
@@ -232,7 +239,9 @@ class WelcomeScreen extends Component {
232 239
         },
233 240
         options: {
234 241
           topBar: {
235
-            title: 'pushed',
242
+            title: {
243
+              text: 'pushed'
244
+            },
236 245
             visible: true,
237 246
             testID: testIDs.TOP_BAR_ELEMENT
238 247
           }
@@ -299,10 +308,14 @@ class WelcomeScreen extends Component {
299 308
               },
300 309
               options: {
301 310
                 topTab: {
302
-                  title: 'Tab 1'
311
+                  title: {
312
+                    text: 'Tab 1'
313
+                  }
303 314
                 },
304 315
                 topBar: {
305
-                  title: 'One'
316
+                  title: {
317
+                    text: 'One'
318
+                  }
306 319
                 }
307 320
               }
308 321
             }
@@ -320,7 +333,9 @@ class WelcomeScreen extends Component {
320 333
                   titleFontFamily: 'HelveticaNeue-Italic'
321 334
                 },
322 335
                 topBar: {
323
-                  title: 'Two'
336
+                  title: {
337
+                    text: 'Two'
338
+                  }
324 339
                 }
325 340
               }
326 341
             }
@@ -337,7 +352,9 @@ class WelcomeScreen extends Component {
337 352
                   title: 'Tab 3'
338 353
                 },
339 354
                 topBar: {
340
-                  title: 'Three'
355
+                  title: {
356
+                    text: 'Three'
357
+                  }
341 358
                 }
342 359
               }
343 360
             }
@@ -385,7 +402,9 @@ class WelcomeScreen extends Component {
385 402
     });
386 403
     Navigation.setOptions('my unique id', {
387 404
       topBar: {
388
-        title: 'User provided id'
405
+        title: {
406
+          text: 'User provided id'
407
+        }
389 408
       }
390 409
     });
391 410
   }

+ 1
- 0
playground/src/testIDs.js 查看文件

@@ -9,6 +9,7 @@ module.exports = {
9 9
   PUSH_BUTTON: `PUSH_BUTTON`,
10 10
   PUSH_OPTIONS_BUTTON: `PUSH_OPTIONS_BUTTON`,
11 11
   PUSH_DEFAULT_OPTIONS_BUTTON: `PUSH_DEFAULT_OPTIONS_BUTTON`,
12
+  SHOW_TOPBAR_REACT_VIEW: `SHOW_TOPBAR_REACT_VIEW`,
12 13
   BACK_HANDLER_BUTTON: `BACK_HANDLER_BUTTON`,
13 14
   SHOW_MODAL_BUTTON: `SHOW_MODAL_BUTTON`,
14 15
   SHOW_REDBOX_BUTTON: `SHOW_REDBOX_BUTTON`,