Bläddra i källkod

Implement drawBehind BottomTabs

Fixes #2996
Guy Carmeli 6 år sedan
förälder
incheckning
c2cc2ff191

+ 8
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java Visa fil

27
         options.currentTabId = TextParser.parse(json, "currentTabId");
27
         options.currentTabId = TextParser.parse(json, "currentTabId");
28
 		options.currentTabIndex = NumberParser.parse(json,"currentTabIndex");
28
 		options.currentTabIndex = NumberParser.parse(json,"currentTabIndex");
29
 		options.visible = BoolParser.parse(json,"visible");
29
 		options.visible = BoolParser.parse(json,"visible");
30
+        options.drawBehind = BoolParser.parse(json, "drawBehind");
30
 		options.animate = BoolParser.parse(json,"animate");
31
 		options.animate = BoolParser.parse(json,"animate");
31
         options.testId = TextParser.parse(json, "testID");
32
         options.testId = TextParser.parse(json, "testID");
32
 
33
 
37
     public Color tabColor = new NullColor();
38
     public Color tabColor = new NullColor();
38
     public Color selectedTabColor = new NullColor();
39
     public Color selectedTabColor = new NullColor();
39
 	public Bool visible = new NullBool();
40
 	public Bool visible = new NullBool();
41
+    public Bool drawBehind = new NullBool();
40
 	public Bool animate = new NullBool();
42
 	public Bool animate = new NullBool();
41
 	public Number currentTabIndex = new NullNumber();
43
 	public Number currentTabIndex = new NullNumber();
42
 	public Text currentTabId = new NullText();
44
 	public Text currentTabId = new NullText();
52
 		if (other.visible.hasValue()) {
54
 		if (other.visible.hasValue()) {
53
 			visible = other.visible;
55
 			visible = other.visible;
54
 		}
56
 		}
57
+        if (other.drawBehind.hasValue()) {
58
+            drawBehind = other.drawBehind;
59
+        }
55
 		if (other.animate.hasValue()) {
60
 		if (other.animate.hasValue()) {
56
 			animate = other.animate;
61
 			animate = other.animate;
57
 		}
62
 		}
79
         if (!visible.hasValue()) {
84
         if (!visible.hasValue()) {
80
             visible = defaultOptions.visible;
85
             visible = defaultOptions.visible;
81
         }
86
         }
87
+        if (!drawBehind.hasValue()) {
88
+            drawBehind = defaultOptions.drawBehind;
89
+        }
82
         if (!animate.hasValue()) {
90
         if (!animate.hasValue()) {
83
             animate = defaultOptions.animate;
91
             animate = defaultOptions.animate;
84
         }
92
         }

+ 27
- 7
lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsOptionsPresenter.java Visa fil

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
+import android.view.ViewGroup.MarginLayoutParams;
4
+
3
 import com.reactnativenavigation.anim.BottomTabsAnimator;
5
 import com.reactnativenavigation.anim.BottomTabsAnimator;
4
 import com.reactnativenavigation.parse.AnimationsOptions;
6
 import com.reactnativenavigation.parse.AnimationsOptions;
5
 import com.reactnativenavigation.parse.BottomTabOptions;
7
 import com.reactnativenavigation.parse.BottomTabOptions;
6
 import com.reactnativenavigation.parse.BottomTabsOptions;
8
 import com.reactnativenavigation.parse.BottomTabsOptions;
7
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
10
+import com.reactnativenavigation.viewcontrollers.ViewController;
8
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
11
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
9
 import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector;
12
 import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector;
10
 import com.reactnativenavigation.views.BottomTabs;
13
 import com.reactnativenavigation.views.BottomTabs;
14
+import com.reactnativenavigation.views.Component;
15
+
16
+import java.util.List;
11
 
17
 
12
 public class BottomTabsOptionsPresenter {
18
 public class BottomTabsOptionsPresenter {
13
-    private BottomTabs bottomTabs;
14
-    private TabSelector tabSelector;
15
-    private BottomTabFinder bottomTabFinder;
16
-    private BottomTabsAnimator animator;
19
+    private final BottomTabs bottomTabs;
20
+    private final TabSelector tabSelector;
21
+    private final BottomTabFinder bottomTabFinder;
22
+    private final BottomTabsAnimator animator;
23
+    private final List<ViewController> tabs;
17
 
24
 
18
-    public BottomTabsOptionsPresenter(BottomTabs bottomTabs, TabSelector tabSelector, BottomTabFinder bottomTabFinder) {
25
+    public BottomTabsOptionsPresenter(BottomTabs bottomTabs, List<ViewController> tabs, TabSelector tabSelector, BottomTabFinder bottomTabFinder) {
19
         this.bottomTabs = bottomTabs;
26
         this.bottomTabs = bottomTabs;
27
+        this.tabs = tabs;
20
         this.tabSelector = tabSelector;
28
         this.tabSelector = tabSelector;
21
         this.bottomTabFinder = bottomTabFinder;
29
         this.bottomTabFinder = bottomTabFinder;
22
         animator = new BottomTabsAnimator(bottomTabs);
30
         animator = new BottomTabsAnimator(bottomTabs);
26
         applyBottomTabsOptions(options.bottomTabsOptions, options.animations);
34
         applyBottomTabsOptions(options.bottomTabsOptions, options.animations);
27
     }
35
     }
28
 
36
 
29
-    public void present(Options options, int tabIndex) {
37
+    public void presentChildOptions(Options options, Component child) {
30
         applyBottomTabsOptions(options.bottomTabsOptions, options.animations);
38
         applyBottomTabsOptions(options.bottomTabsOptions, options.animations);
39
+        int tabIndex = bottomTabFinder.findByComponent(child);
31
         applyBottomTabOptions(options.bottomTabOptions, tabIndex);
40
         applyBottomTabOptions(options.bottomTabOptions, tabIndex);
41
+        applyDrawBehind(options.bottomTabsOptions, tabIndex);
32
     }
42
     }
33
 
43
 
34
     private void applyBottomTabOptions(BottomTabOptions options, int tabIndex) {
44
     private void applyBottomTabOptions(BottomTabOptions options, int tabIndex) {
37
         }
47
         }
38
     }
48
     }
39
 
49
 
50
+    private void applyDrawBehind(BottomTabsOptions options, int tabIndex) {
51
+        MarginLayoutParams lp = (MarginLayoutParams) tabs.get(tabIndex).getView().getLayoutParams();
52
+        if (options.drawBehind.isTrue()) {
53
+            lp.bottomMargin = 0;
54
+        }
55
+        if (options.drawBehind.isFalseOrUndefined()) {
56
+            lp.bottomMargin = bottomTabs.getHeight();
57
+        }
58
+
59
+    }
60
+
40
     private void applyBottomTabsOptions(BottomTabsOptions options, AnimationsOptions animationsOptions) {
61
     private void applyBottomTabsOptions(BottomTabsOptions options, AnimationsOptions animationsOptions) {
41
         if (options.backgroundColor.hasValue()) {
62
         if (options.backgroundColor.hasValue()) {
42
             bottomTabs.setBackgroundColor(options.backgroundColor.get());
63
             bottomTabs.setBackgroundColor(options.backgroundColor.get());
73
             }
94
             }
74
         }
95
         }
75
     }
96
     }
76
-
77
 }
97
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabFinder.java Visa fil

11
     private List<ViewController> tabs;
11
     private List<ViewController> tabs;
12
 
12
 
13
     @IntRange(from = -1)
13
     @IntRange(from = -1)
14
-    int findByComponent(Component component) {
14
+    public int findByComponent(Component component) {
15
         for (int i = 0; i < tabs.size(); i++) {
15
         for (int i = 0; i < tabs.size(); i++) {
16
             if (tabs.get(i).containsComponent(component)) {
16
             if (tabs.get(i).containsComponent(component)) {
17
                 return i;
17
                 return i;

+ 10
- 8
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java Visa fil

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.graphics.drawable.Drawable;
4
 import android.graphics.drawable.Drawable;
5
 import android.support.annotation.NonNull;
5
 import android.support.annotation.NonNull;
6
+import android.support.annotation.RestrictTo;
6
 import android.view.ViewGroup;
7
 import android.view.ViewGroup;
7
 import android.widget.RelativeLayout;
8
 import android.widget.RelativeLayout;
8
 
9
 
48
 	protected ViewGroup createView() {
49
 	protected ViewGroup createView() {
49
 		RelativeLayout root = new RelativeLayout(getActivity());
50
 		RelativeLayout root = new RelativeLayout(getActivity());
50
 		bottomTabs = new BottomTabs(getActivity());
51
 		bottomTabs = new BottomTabs(getActivity());
51
-        presenter = new BottomTabsOptionsPresenter(bottomTabs, this, bottomTabFinder);
52
+        presenter = new BottomTabsOptionsPresenter(bottomTabs, tabs, this, bottomTabFinder);
52
         bottomTabs.setOnTabSelectedListener(this);
53
         bottomTabs.setOnTabSelectedListener(this);
53
 		RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
54
 		RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
54
 		lp.addRule(ALIGN_PARENT_BOTTOM);
55
 		lp.addRule(ALIGN_PARENT_BOTTOM);
65
     @Override
66
     @Override
66
     public void applyChildOptions(Options options, Component child) {
67
     public void applyChildOptions(Options options, Component child) {
67
         super.applyChildOptions(options, child);
68
         super.applyChildOptions(options, child);
68
-        final int tabIndex = bottomTabFinder.findByComponent(child);
69
-        if (tabIndex >= 0) presenter.present(this.options, tabIndex);
69
+        presenter.presentChildOptions(this.options, child);
70
         applyOnParentController(parentController ->
70
         applyOnParentController(parentController ->
71
                 ((ParentController) parentController).applyChildOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), child)
71
                 ((ParentController) parentController).applyChildOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), child)
72
         );
72
         );
75
     @Override
75
     @Override
76
     public void mergeChildOptions(Options options, Component child) {
76
     public void mergeChildOptions(Options options, Component child) {
77
         super.mergeChildOptions(options, child);
77
         super.mergeChildOptions(options, child);
78
-        final int tabIndex = bottomTabFinder.findByComponent(child);
79
-        presenter.present(options, tabIndex);
78
+        presenter.presentChildOptions(options, child);
80
         applyOnParentController(parentController ->
79
         applyOnParentController(parentController ->
81
                 ((ParentController) parentController).mergeChildOptions(options.copy().clearBottomTabsOptions(), child)
80
                 ((ParentController) parentController).mergeChildOptions(options.copy().clearBottomTabsOptions(), child)
82
         );
81
         );
169
     public void selectTab(final int newIndex) {
168
     public void selectTab(final int newIndex) {
170
         getView().removeView(getCurrentView());
169
         getView().removeView(getCurrentView());
171
         bottomTabs.setCurrentItem(newIndex, false);
170
         bottomTabs.setCurrentItem(newIndex, false);
172
-        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
173
-        params.bottomMargin = bottomTabs.getHeight();
174
-        getView().addView(getCurrentView(), params);
171
+        getView().addView(getCurrentView());
175
     }
172
     }
176
 
173
 
177
     @NonNull
174
     @NonNull
178
     private ViewGroup getCurrentView() {
175
     private ViewGroup getCurrentView() {
179
         return tabs.get(bottomTabs.getCurrentItem()).getView();
176
         return tabs.get(bottomTabs.getCurrentItem()).getView();
180
     }
177
     }
178
+
179
+    @RestrictTo(RestrictTo.Scope.TESTS)
180
+    public BottomTabs getBottomTabs() {
181
+        return bottomTabs;
182
+    }
181
 }
183
 }

+ 38
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java Visa fil

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
+import android.view.ViewGroup;
5
 import android.widget.RelativeLayout;
6
 import android.widget.RelativeLayout;
6
 
7
 
7
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.BaseTest;
11
 import com.reactnativenavigation.mocks.TopBarBackgroundViewCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarBackgroundViewCreatorMock;
12
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13
 import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.Options;
15
+import com.reactnativenavigation.parse.params.Bool;
14
 import com.reactnativenavigation.parse.params.Color;
16
 import com.reactnativenavigation.parse.params.Color;
15
 import com.reactnativenavigation.parse.params.Number;
17
 import com.reactnativenavigation.parse.params.Number;
18
+import com.reactnativenavigation.parse.params.Text;
16
 import com.reactnativenavigation.react.EventEmitter;
19
 import com.reactnativenavigation.react.EventEmitter;
17
 import com.reactnativenavigation.utils.CommandListenerAdapter;
20
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18
 import com.reactnativenavigation.utils.ImageLoader;
21
 import com.reactnativenavigation.utils.ImageLoader;
51
     private ImageLoader imageLoaderMock = ImageLoaderMock.mock();
54
     private ImageLoader imageLoaderMock = ImageLoaderMock.mock();
52
     private EventEmitter eventEmitter;
55
     private EventEmitter eventEmitter;
53
     private ChildControllersRegistry childRegistry;
56
     private ChildControllersRegistry childRegistry;
57
+    private List<ViewController> tabs;
54
 
58
 
55
     @Override
59
     @Override
56
     public void beforeEach() {
60
     public void beforeEach() {
57
         activity = newActivity();
61
         activity = newActivity();
58
         childRegistry = new ChildControllersRegistry();
62
         childRegistry = new ChildControllersRegistry();
59
         eventEmitter = Mockito.mock(EventEmitter.class);
63
         eventEmitter = Mockito.mock(EventEmitter.class);
60
-        uut = spy(new BottomTabsController(activity, childRegistry, eventEmitter, imageLoaderMock, "uut", new Options()));
64
+        uut = spy(new BottomTabsController(activity, childRegistry, eventEmitter, imageLoaderMock, "uut", new Options()) {
65
+            @Override
66
+            public void ensureViewIsCreated() {
67
+                super.ensureViewIsCreated();
68
+                uut.getView().layout(0, 0, 1000, 1000);
69
+                uut.getBottomTabs().layout(0, 0, 1000, 100);
70
+            }
71
+        });
61
         child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions));
72
         child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions));
62
         child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions));
73
         child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions));
63
         child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions));
74
         child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions));
64
         child4 = spy(new SimpleViewController(activity, childRegistry, "child4", tabOptions));
75
         child4 = spy(new SimpleViewController(activity, childRegistry, "child4", tabOptions));
65
         child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions));
76
         child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions));
77
+        tabs = createTabs();
66
     }
78
     }
67
 
79
 
68
     @Test
80
     @Test
169
 
181
 
170
     @Test
182
     @Test
171
     public void mergeOptions_currentTabIndex() {
183
     public void mergeOptions_currentTabIndex() {
172
-        List<ViewController> tabs = createTabs();
173
         uut.setTabs(tabs);
184
         uut.setTabs(tabs);
174
         uut.ensureViewIsCreated();
185
         uut.ensureViewIsCreated();
175
 
186
 
180
         verify(eventEmitter, times(0)).emitBottomTabSelected(any(Integer.class), any(Integer.class));
191
         verify(eventEmitter, times(0)).emitBottomTabSelected(any(Integer.class), any(Integer.class));
181
     }
192
     }
182
 
193
 
194
+    @Test
195
+    public void mergeOptions_drawBehind() {
196
+        List<ViewController> tabs = createTabs();
197
+        uut.setTabs(tabs);
198
+        uut.ensureViewIsCreated();
199
+        child1.onViewAppeared();
200
+        uut.selectTab(0);
201
+
202
+        assertThat(childLayoutParams(0).bottomMargin).isEqualTo(uut.getBottomTabs().getHeight());
203
+
204
+        Options o1 = new Options();
205
+        o1.bottomTabsOptions.drawBehind = new Bool(true);
206
+        child1.mergeOptions(o1);
207
+        assertThat(childLayoutParams(0).bottomMargin).isEqualTo(0);
208
+
209
+        Options o2 = new Options();
210
+        o2.topBar.title.text = new Text("Some text");
211
+        child1.mergeOptions(o1);
212
+        assertThat(childLayoutParams(0).bottomMargin).isEqualTo(0);
213
+    }
214
+
183
     @Test
215
     @Test
184
     public void child_mergeOptions_currentTabIndex() {
216
     public void child_mergeOptions_currentTabIndex() {
185
         List<ViewController> tabs = createTabs();
217
         List<ViewController> tabs = createTabs();
220
                 .setInitialOptions(tabOptions)
252
                 .setInitialOptions(tabOptions)
221
                 .createStackController();
253
                 .createStackController();
222
     }
254
     }
255
+
256
+    private ViewGroup.MarginLayoutParams childLayoutParams(int index) {
257
+        return (ViewGroup.MarginLayoutParams) tabs.get(index).getView().getLayoutParams();
258
+    }
223
 }
259
 }

+ 4
- 1
playground/src/screens/TextScreen.js Visa fil

10
   static get options() {
10
   static get options() {
11
     return {
11
     return {
12
       bottomTabs: {
12
       bottomTabs: {
13
+        drawBehind: true,
13
         testID: testIDs.BOTTOM_TABS_ELEMENT
14
         testID: testIDs.BOTTOM_TABS_ELEMENT
14
       },
15
       },
15
       topBar: {
16
       topBar: {
62
       bottomTabs: {
63
       bottomTabs: {
63
         currentTabIndex: 1,
64
         currentTabIndex: 1,
64
         visible: false,
65
         visible: false,
66
+        drawBehind: true,
65
         animate: true,
67
         animate: true,
66
         tabColor: 'blue',
68
         tabColor: 'blue',
67
         selectedTabColor: 'red'
69
         selectedTabColor: 'red'
81
     Navigation.mergeOptions(this.props.componentId, {
83
     Navigation.mergeOptions(this.props.componentId, {
82
       bottomTabs: {
84
       bottomTabs: {
83
         visible,
85
         visible,
86
+        drawBehind: true,
84
         animate: true
87
         animate: true
85
       }
88
       }
86
     });
89
     });
108
     flexGrow: 1,
111
     flexGrow: 1,
109
     justifyContent: 'center',
112
     justifyContent: 'center',
110
     alignItems: 'center',
113
     alignItems: 'center',
111
-    backgroundColor: '#f5fcff'
114
+    backgroundColor: '#E3DCC3'
112
   },
115
   },
113
   h1: {
116
   h1: {
114
     fontSize: 24,
117
     fontSize: 24,