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
   },
228
   },
229
   layout: {
229
   layout: {
230
     topMargin: Navigation.constants().statusBarHeight, // Set the layout's top margin
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
   topBar: {
234
   topBar: {
234
     height: 70, // TopBar height in dp
235
     height: 70, // TopBar height in dp

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

146
                 new ComponentViewCreator(reactInstanceManager),
146
                 new ComponentViewCreator(reactInstanceManager),
147
                 parse(typefaceManager, node.getOptions()),
147
                 parse(typefaceManager, node.getOptions()),
148
                 new Presenter(activity, defaultOptions),
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
         if (json == null) return result;
15
         if (json == null) return result;
16
 
16
 
17
         result.backgroundColor = ColorParser.parse(json, "backgroundColor");
17
         result.backgroundColor = ColorParser.parse(json, "backgroundColor");
18
+        result.componentBackgroundColor = ColorParser.parse(json, "componentBackgroundColor");
18
         result.topMargin = NumberParser.parse(json, "topMargin");
19
         result.topMargin = NumberParser.parse(json, "topMargin");
19
         result.orientation = OrientationOptions.parse(json);
20
         result.orientation = OrientationOptions.parse(json);
20
 
21
 
22
     }
23
     }
23
 
24
 
24
     public Colour backgroundColor = new NullColor();
25
     public Colour backgroundColor = new NullColor();
26
+    public Colour componentBackgroundColor = new NullColor();
25
     public Number topMargin = new NullNumber();
27
     public Number topMargin = new NullNumber();
26
     public OrientationOptions orientation = new OrientationOptions();
28
     public OrientationOptions orientation = new OrientationOptions();
27
 
29
 
28
     public void mergeWith(LayoutOptions other) {
30
     public void mergeWith(LayoutOptions other) {
29
         if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;
31
         if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;
32
+        if (other.componentBackgroundColor.hasValue()) componentBackgroundColor = other.componentBackgroundColor;
30
         if (other.topMargin.hasValue()) topMargin = other.topMargin;
33
         if (other.topMargin.hasValue()) topMargin = other.topMargin;
31
         if (other.orientation.hasValue()) orientation = other.orientation;
34
         if (other.orientation.hasValue()) orientation = other.orientation;
32
 
35
 
34
 
37
 
35
     public void mergeWithDefault(LayoutOptions defaultOptions) {
38
     public void mergeWithDefault(LayoutOptions defaultOptions) {
36
         if (!backgroundColor.hasValue()) backgroundColor = defaultOptions.backgroundColor;
39
         if (!backgroundColor.hasValue()) backgroundColor = defaultOptions.backgroundColor;
40
+        if (!componentBackgroundColor.hasValue()) componentBackgroundColor = defaultOptions.componentBackgroundColor;
37
         if (!topMargin.hasValue()) topMargin = defaultOptions.topMargin;
41
         if (!topMargin.hasValue()) topMargin = defaultOptions.topMargin;
38
         if (!orientation.hasValue()) orientation = defaultOptions.orientation;
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
 import com.reactnativenavigation.views.ComponentLayout;
4
 import com.reactnativenavigation.views.ComponentLayout;
5
 
5
 
6
 public class ComponentPresenter {
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
     public void mergeOptions(ComponentLayout view, Options options) {
21
     public void mergeOptions(ComponentLayout view, Options options) {
9
         if (options.overlayOptions.interceptTouchOutside.hasValue()) view.setInterceptTouchOutside(options.overlayOptions.interceptTouchOutside);
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
         this.presenter = componentPresenter;
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
     @Override
39
     @Override
34
     public void onViewAppeared() {
40
     public void onViewAppeared() {
35
         super.onViewAppeared();
41
         super.onViewAppeared();
50
     @Override
56
     @Override
51
     public void applyOptions(Options options) {
57
     public void applyOptions(Options options) {
52
         super.applyOptions(options);
58
         super.applyOptions(options);
53
-        view.applyOptions(options);
59
+        getView().applyOptions(options);
60
+        presenter.applyOptions(getView(), resolveCurrentOptions(presenter.defaultOptions));
54
     }
61
     }
55
 
62
 
56
     @Override
63
     @Override

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

9
 
9
 
10
 public class SimpleComponentViewController extends ComponentViewController {
10
 public class SimpleComponentViewController extends ComponentViewController {
11
     public SimpleComponentViewController(Activity activity, ChildControllersRegistry childRegistry, String id, Options initialOptions) {
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
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.presentation.ComponentPresenter;
10
 import com.reactnativenavigation.presentation.ComponentPresenter;
11
 import com.reactnativenavigation.presentation.Presenter;
11
 import com.reactnativenavigation.presentation.Presenter;
12
+import com.reactnativenavigation.views.ComponentLayout;
12
 import com.reactnativenavigation.views.StackLayout;
13
 import com.reactnativenavigation.views.StackLayout;
13
 
14
 
14
 import org.junit.Test;
15
 import org.junit.Test;
22
 
23
 
23
 public class ComponentViewControllerTest extends BaseTest {
24
 public class ComponentViewControllerTest extends BaseTest {
24
     private ComponentViewController uut;
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
     @Override
30
     @Override
29
     public void beforeEach() {
31
     public void beforeEach() {
32
         view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
34
         view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
33
         ParentController<StackLayout> parentController = TestUtils.newStackController(activity).build();
35
         ParentController<StackLayout> parentController = TestUtils.newStackController(activity).build();
34
         Presenter presenter = new Presenter(activity, new Options());
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
         uut.setParentController(parentController);
44
         uut.setParentController(parentController);
38
         parentController.ensureViewIsCreated();
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
     @Test
63
     @Test
42
     public void createsViewFromComponentViewCreator() {
64
     public void createsViewFromComponentViewCreator() {
43
         assertThat(uut.getView()).isSameAs(view);
65
         assertThat(uut.getView()).isSameAs(view);
93
     public void mergeOptions_delegatesToPresenter() {
115
     public void mergeOptions_delegatesToPresenter() {
94
         Options options = new Options();
116
         Options options = new Options();
95
         uut.mergeOptions(options);
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
                 (activity1, componentId, componentName) -> view,
63
                 (activity1, componentId, componentName) -> view,
64
                 initialNavigationOptions,
64
                 initialNavigationOptions,
65
                 new Presenter(activity, new Options()),
65
                 new Presenter(activity, new Options()),
66
-                new ComponentPresenter()
66
+                new ComponentPresenter(Options.EMPTY)
67
         ) {
67
         ) {
68
             @Override
68
             @Override
69
             public boolean isViewShown() {
69
             public boolean isViewShown() {

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

92
                     new TestComponentViewCreator(),
92
                     new TestComponentViewCreator(),
93
                     tabOptions.get(i),
93
                     tabOptions.get(i),
94
                     new Presenter(activity, new Options()),
94
                     new Presenter(activity, new Options()),
95
-                    new ComponentPresenter()
95
+                    new ComponentPresenter(Options.EMPTY)
96
             );
96
             );
97
             tabControllers.add(spy(viewController));
97
             tabControllers.add(spy(viewController));
98
         }
98
         }

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

55
    * Set the screen background color
55
    * Set the screen background color
56
    */
56
    */
57
   backgroundColor?: Color;
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
    * Set the allowed orientations
63
    * Set the allowed orientations
60
    */
64
    */

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

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

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

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