Browse Source

Add layout.componentBackgroundColor

This property is used to set background color only for components,
unlike backgroundColor which sets color for every type of layout.

Motivation
When a view appears, its options are resolved according to its
currently displayed children. Basically this means that child options
are hoisted to the parent as children can declare options which effect
their parent.
This means that if a component has declared layout.backgroundColor or
if that property was declared in defaultOptions, each view will have a
background color, which might contribute to a significant overdraw.
Guy Carmeli 5 years ago
parent
commit
cb48065aaf

+ 2
- 1
docs/docs/styling.md View File

@@ -228,7 +228,8 @@ Navigation.mergeOptions(this.props.componentId, {
228 228
   },
229 229
   layout: {
230 230
     topMargin: Navigation.constants().statusBarHeight, // Set the layout's top margin
231
-    orientation: ['portrait', 'landscape'] | ['sensorLandscape'] // An array of supported orientations
231
+    orientation: ['portrait', 'landscape'] | ['sensorLandscape'], // An array of supported orientations
232
+    componentBackgroundColor: 'red' // Set background color only for components, helps reduce overdraw if background color is set in default options.
232 233
   },
233 234
   topBar: {
234 235
     height: 70, // TopBar height in dp

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java View File

@@ -146,7 +146,7 @@ public class LayoutFactory {
146 146
                 new ComponentViewCreator(reactInstanceManager),
147 147
                 parse(typefaceManager, node.getOptions()),
148 148
                 new Presenter(activity, defaultOptions),
149
-                new ComponentPresenter()
149
+                new ComponentPresenter(defaultOptions)
150 150
         );
151 151
 	}
152 152
 

+ 4
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutOptions.java View File

@@ -15,6 +15,7 @@ public class LayoutOptions {
15 15
         if (json == null) return result;
16 16
 
17 17
         result.backgroundColor = ColorParser.parse(json, "backgroundColor");
18
+        result.componentBackgroundColor = ColorParser.parse(json, "componentBackgroundColor");
18 19
         result.topMargin = NumberParser.parse(json, "topMargin");
19 20
         result.orientation = OrientationOptions.parse(json);
20 21
 
@@ -22,11 +23,13 @@ public class LayoutOptions {
22 23
     }
23 24
 
24 25
     public Colour backgroundColor = new NullColor();
26
+    public Colour componentBackgroundColor = new NullColor();
25 27
     public Number topMargin = new NullNumber();
26 28
     public OrientationOptions orientation = new OrientationOptions();
27 29
 
28 30
     public void mergeWith(LayoutOptions other) {
29 31
         if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;
32
+        if (other.componentBackgroundColor.hasValue()) componentBackgroundColor = other.componentBackgroundColor;
30 33
         if (other.topMargin.hasValue()) topMargin = other.topMargin;
31 34
         if (other.orientation.hasValue()) orientation = other.orientation;
32 35
 
@@ -34,6 +37,7 @@ public class LayoutOptions {
34 37
 
35 38
     public void mergeWithDefault(LayoutOptions defaultOptions) {
36 39
         if (!backgroundColor.hasValue()) backgroundColor = defaultOptions.backgroundColor;
40
+        if (!componentBackgroundColor.hasValue()) componentBackgroundColor = defaultOptions.componentBackgroundColor;
37 41
         if (!topMargin.hasValue()) topMargin = defaultOptions.topMargin;
38 42
         if (!orientation.hasValue()) orientation = defaultOptions.orientation;
39 43
     }

+ 20
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/ComponentPresenter.java View File

@@ -4,8 +4,28 @@ import com.reactnativenavigation.parse.Options;
4 4
 import com.reactnativenavigation.views.ComponentLayout;
5 5
 
6 6
 public class ComponentPresenter {
7
+    public Options defaultOptions;
8
+
9
+    public ComponentPresenter(Options defaultOptions) {
10
+        this.defaultOptions = defaultOptions;
11
+    }
12
+
13
+    public void setDefaultOptions(Options defaultOptions) {
14
+        this.defaultOptions = defaultOptions;
15
+    }
16
+
17
+    public void applyOptions(ComponentLayout view, Options options) {
18
+        mergeBackgroundColor(view, options);
19
+    }
7 20
 
8 21
     public void mergeOptions(ComponentLayout view, Options options) {
9 22
         if (options.overlayOptions.interceptTouchOutside.hasValue()) view.setInterceptTouchOutside(options.overlayOptions.interceptTouchOutside);
23
+        mergeBackgroundColor(view, options);
24
+    }
25
+
26
+    private void mergeBackgroundColor(ComponentLayout view, Options options) {
27
+        if (options.layout.componentBackgroundColor.hasValue()) {
28
+            view.setBackgroundColor(options.layout.componentBackgroundColor.get());
29
+        }
10 30
     }
11 31
 }

+ 8
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java View File

@@ -30,6 +30,12 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
30 30
         this.presenter = componentPresenter;
31 31
     }
32 32
 
33
+    @Override
34
+    public void setDefaultOptions(Options defaultOptions) {
35
+        super.setDefaultOptions(defaultOptions);
36
+        presenter.setDefaultOptions(defaultOptions);
37
+    }
38
+
33 39
     @Override
34 40
     public void onViewAppeared() {
35 41
         super.onViewAppeared();
@@ -50,7 +56,8 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
50 56
     @Override
51 57
     public void applyOptions(Options options) {
52 58
         super.applyOptions(options);
53
-        view.applyOptions(options);
59
+        getView().applyOptions(options);
60
+        presenter.applyOptions(getView(), resolveCurrentOptions(presenter.defaultOptions));
54 61
     }
55 62
 
56 63
     @Override

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleComponentViewController.java View File

@@ -9,6 +9,6 @@ import com.reactnativenavigation.viewcontrollers.*;
9 9
 
10 10
 public class SimpleComponentViewController extends ComponentViewController {
11 11
     public SimpleComponentViewController(Activity activity, ChildControllersRegistry childRegistry, String id, Options initialOptions) {
12
-        super(activity, childRegistry,id, "theComponentName", new TestComponentViewCreator(), initialOptions, new Presenter(activity, new Options()), new ComponentPresenter());
12
+        super(activity, childRegistry,id, "theComponentName", new TestComponentViewCreator(), initialOptions, new Presenter(activity, new Options()), new ComponentPresenter(Options.EMPTY));
13 13
     }
14 14
 }

+ 27
- 5
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java View File

@@ -9,6 +9,7 @@ import com.reactnativenavigation.mocks.TestReactView;
9 9
 import com.reactnativenavigation.parse.Options;
10 10
 import com.reactnativenavigation.presentation.ComponentPresenter;
11 11
 import com.reactnativenavigation.presentation.Presenter;
12
+import com.reactnativenavigation.views.ComponentLayout;
12 13
 import com.reactnativenavigation.views.StackLayout;
13 14
 
14 15
 import org.junit.Test;
@@ -22,8 +23,9 @@ import static org.mockito.Mockito.when;
22 23
 
23 24
 public class ComponentViewControllerTest extends BaseTest {
24 25
     private ComponentViewController uut;
25
-    private IReactView view;
26
-    private ComponentPresenter componentPresenter;
26
+    private ComponentLayout view;
27
+    private ComponentPresenter presenter;
28
+    private Options resolvedOptions = new Options();
27 29
 
28 30
     @Override
29 31
     public void beforeEach() {
@@ -32,12 +34,32 @@ public class ComponentViewControllerTest extends BaseTest {
32 34
         view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
33 35
         ParentController<StackLayout> parentController = TestUtils.newStackController(activity).build();
34 36
         Presenter presenter = new Presenter(activity, new Options());
35
-        this.componentPresenter = spy(new ComponentPresenter());
36
-        uut = new ComponentViewController(activity, new ChildControllersRegistry(), "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options(), presenter, this.componentPresenter);
37
+        this.presenter = spy(new ComponentPresenter(Options.EMPTY));
38
+        uut = new ComponentViewController(activity, new ChildControllersRegistry(), "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options(), presenter, this.presenter) {
39
+            @Override
40
+            public Options resolveCurrentOptions(Options defaultOptions) {
41
+                return resolvedOptions;
42
+            }
43
+        };
37 44
         uut.setParentController(parentController);
38 45
         parentController.ensureViewIsCreated();
39 46
     }
40 47
 
48
+    @Test
49
+    public void setDefaultOptions() {
50
+        Options defaultOptions = new Options();
51
+        uut.setDefaultOptions(defaultOptions);
52
+        verify(presenter).setDefaultOptions(defaultOptions);
53
+    }
54
+
55
+    @Test
56
+    public void applyOptions() {
57
+        Options options = new Options();
58
+        uut.applyOptions(options);
59
+        verify(view).applyOptions(options);
60
+        verify(presenter).applyOptions(view, resolvedOptions);
61
+    }
62
+
41 63
     @Test
42 64
     public void createsViewFromComponentViewCreator() {
43 65
         assertThat(uut.getView()).isSameAs(view);
@@ -93,6 +115,6 @@ public class ComponentViewControllerTest extends BaseTest {
93 115
     public void mergeOptions_delegatesToPresenter() {
94 116
         Options options = new Options();
95 117
         uut.mergeOptions(options);
96
-        verify(componentPresenter).mergeOptions(uut.getView(), options);
118
+        verify(presenter).mergeOptions(uut.getView(), options);
97 119
     }
98 120
 }

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java View File

@@ -63,7 +63,7 @@ public class OptionsApplyingTest extends BaseTest {
63 63
                 (activity1, componentId, componentName) -> view,
64 64
                 initialNavigationOptions,
65 65
                 new Presenter(activity, new Options()),
66
-                new ComponentPresenter()
66
+                new ComponentPresenter(Options.EMPTY)
67 67
         ) {
68 68
             @Override
69 69
             public boolean isViewShown() {

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java View File

@@ -92,7 +92,7 @@ public class TopTabsViewControllerTest extends BaseTest {
92 92
                     new TestComponentViewCreator(),
93 93
                     tabOptions.get(i),
94 94
                     new Presenter(activity, new Options()),
95
-                    new ComponentPresenter()
95
+                    new ComponentPresenter(Options.EMPTY)
96 96
             );
97 97
             tabControllers.add(spy(viewController));
98 98
         }

+ 4
- 0
lib/src/interfaces/Options.ts View File

@@ -55,6 +55,10 @@ export interface OptionsLayout {
55 55
    * Set the screen background color
56 56
    */
57 57
   backgroundColor?: Color;
58
+  /**
59
+   * Set background color only for components, helps reduce overdraw if background color is set in default options.
60
+   */
61
+  componentBackgroundColor?: Color;
58 62
   /**
59 63
    * Set the allowed orientations
60 64
    */

+ 3
- 0
playground/src/app.js View File

@@ -24,6 +24,9 @@ function start() {
24 24
   registerScreens();
25 25
   Navigation.events().registerAppLaunchedListener(async () => {
26 26
     Navigation.setDefaultOptions({
27
+      layout: {
28
+        componentBackgroundColor: '#e8e8e8'
29
+      },
27 30
       bottomTab: {
28 31
         iconColor: '#1B4C77',
29 32
         selectedIconColor: '#0f0',

+ 0
- 2
playground/src/screens/WelcomeScreen.js View File

@@ -583,12 +583,10 @@ const styles = {
583 583
     flexGrow: 1,
584 584
     justifyContent: 'center',
585 585
     alignItems: 'center',
586
-    backgroundColor: '#e8e8e8',
587 586
   },
588 587
   bar: {
589 588
     flex: 1,
590 589
     flexDirection: 'column',
591
-    backgroundColor: '#e8e8e8',
592 590
     justifyContent: 'space-between'
593 591
   },
594 592
   h1: {