Browse Source

Support tabs without icons on Android (#5978)

This commit introduces parity with iOS which allows the user to show tabs without icons. While there's no real production use case for this feature, it's helpful when getting started with a new project.
Guy Carmeli 4 years ago
parent
commit
ef58a6cdeb
No account linked to committer's email address

+ 1
- 1
lib/android/app/build.gradle View File

@@ -161,7 +161,7 @@ dependencies {
161 161
     implementation 'androidx.annotation:annotation:1.1.0'
162 162
     implementation 'com.google.android.material:material:1.2.0-alpha03'
163 163
 
164
-    implementation 'com.github.wix-playground:ahbottomnavigation:3.1.2'
164
+    implementation 'com.github.wix-playground:ahbottomnavigation:3.2.0'
165 165
     implementation 'com.github.wix-playground:reflow-animator:1.0.6'
166 166
     implementation 'com.github.clans:fab:1.6.4'
167 167
 

+ 11
- 1
lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java View File

@@ -13,6 +13,8 @@ import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
13 13
 import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector;
14 14
 import com.reactnativenavigation.views.BottomTabs;
15 15
 
16
+import org.jetbrains.annotations.NotNull;
17
+
16 18
 import java.util.List;
17 19
 
18 20
 import androidx.annotation.IntRange;
@@ -118,7 +120,7 @@ public class BottomTabsPresenter {
118 120
 
119 121
         bottomTabs.setLayoutDirection(options.layout.direction);
120 122
         bottomTabs.setPreferLargeIcons(options.bottomTabsOptions.preferLargeIcons.get(false));
121
-        bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode.get(TitleState.SHOW_WHEN_ACTIVE));
123
+        bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode.get(getDefaultTitleState()));
122 124
         bottomTabs.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE));
123 125
         if (bottomTabsOptions.currentTabIndex.hasValue()) {
124 126
             int tabIndex = bottomTabsOptions.currentTabIndex.get();
@@ -148,6 +150,14 @@ public class BottomTabsPresenter {
148 150
         }
149 151
     }
150 152
 
153
+    @NotNull
154
+    private TitleState getDefaultTitleState() {
155
+        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
156
+            if (bottomTabs.getItem(i).hasIcon()) return TitleState.SHOW_WHEN_ACTIVE;
157
+        }
158
+        return TitleState.ALWAYS_SHOW;
159
+    }
160
+
151 161
     public void applyBottomInset(int bottomInset) {
152 162
         ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) bottomTabs.getLayoutParams();
153 163
         lp.bottomMargin = bottomInset;

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

@@ -164,7 +164,7 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
164 164
             BottomTabOptions options = tab.resolveCurrentOptions().bottomTabOptions;
165 165
             return new AHBottomNavigationItem(
166 166
                     options.text.get(""),
167
-                    imageLoader.loadIcon(getActivity(), options.icon.get()),
167
+                    imageLoader.loadIcon(getActivity(), options.icon.get(null)),
168 168
                     imageLoader.loadIcon(getActivity(), options.selectedIcon.get(null)),
169 169
                     options.testId.get("")
170 170
             );

+ 50
- 24
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java View File

@@ -6,6 +6,7 @@ import android.view.Gravity;
6 6
 import android.view.View;
7 7
 import android.view.ViewGroup.MarginLayoutParams;
8 8
 
9
+import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
9 10
 import com.reactnativenavigation.BaseTest;
10 11
 import com.reactnativenavigation.TestUtils;
11 12
 import com.reactnativenavigation.mocks.ImageLoaderMock;
@@ -13,6 +14,7 @@ import com.reactnativenavigation.mocks.SimpleViewController;
13 14
 import com.reactnativenavigation.parse.Options;
14 15
 import com.reactnativenavigation.parse.params.Bool;
15 16
 import com.reactnativenavigation.parse.params.Colour;
17
+import com.reactnativenavigation.parse.params.NullText;
16 18
 import com.reactnativenavigation.parse.params.Number;
17 19
 import com.reactnativenavigation.parse.params.Text;
18 20
 import com.reactnativenavigation.presentation.BottomTabPresenter;
@@ -43,6 +45,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout;
43 45
 import edu.emory.mathcs.backport.java.util.Collections;
44 46
 
45 47
 import static com.reactnativenavigation.TestUtils.hideBackButton;
48
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
46 49
 import static org.assertj.core.api.Java6Assertions.assertThat;
47 50
 import static org.mockito.ArgumentMatchers.any;
48 51
 import static org.mockito.ArgumentMatchers.eq;
@@ -74,32 +77,9 @@ public class BottomTabsControllerTest extends BaseTest {
74 77
     @Override
75 78
     public void beforeEach() {
76 79
         activity = newActivity();
77
-        bottomTabs = spy(new BottomTabs(activity) {
78
-            @Override
79
-            public void superCreateItems() {
80
-
81
-            }
82
-        });
83 80
         childRegistry = new ChildControllersRegistry();
84 81
         eventEmitter = Mockito.mock(EventEmitter.class);
85
-
86
-        child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions));
87
-        child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions));
88
-        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions));
89
-        child4 = spy(createStack());
90
-        child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions));
91
-        when(child5.handleBack(any())).thenReturn(true);
92
-        tabs = createTabs();
93
-        presenter = spy(new BottomTabsPresenter(tabs, new Options()));
94
-        bottomTabPresenter = spy(new BottomTabPresenter(activity, tabs, ImageLoaderMock.mock(), new Options()));
95
-        tabsAttacher = spy(new BottomTabsAttacher(tabs, presenter));
96
-        uut = createBottomTabs();
97
-
98
-        uut.setParentController(Mockito.mock(ParentController.class));
99
-        CoordinatorLayout parent = new CoordinatorLayout(activity);
100
-        parent.addView(uut.getView());
101
-        activity.setContentView(parent);
102
-
82
+        prepareViewsForTests();
103 83
         StatusBarUtils.saveStatusBarHeight(63);
104 84
     }
105 85
 
@@ -110,6 +90,22 @@ public class BottomTabsControllerTest extends BaseTest {
110 90
         assertThat(((CoordinatorLayout.LayoutParams) uut.getBottomTabs().getLayoutParams()).gravity).isEqualTo(Gravity.BOTTOM);
111 91
     }
112 92
 
93
+    @Test
94
+    public void createView_tabsWithoutIconsAreAccepted() {
95
+        tabOptions.bottomTabOptions.icon = new NullText();
96
+        prepareViewsForTests();
97
+        assertThat(uut.getBottomTabs().getItemsCount()).isEqualTo(tabs.size());
98
+    }
99
+
100
+    @Test
101
+    public void createView_showTitlesWhenAllTabsDontHaveIcons() {
102
+        tabOptions.bottomTabOptions.icon = new NullText();
103
+        assertThat(tabOptions.bottomTabsOptions.titleDisplayMode.hasValue()).isFalse();
104
+        prepareViewsForTests();
105
+        presenter.applyOptions(Options.EMPTY);
106
+        assertThat(bottomTabs.getTitleState()).isEqualTo(AHBottomNavigation.TitleState.ALWAYS_SHOW);
107
+    }
108
+
113 109
     @Test(expected = RuntimeException.class)
114 110
     public void setTabs_ThrowWhenMoreThan5() {
115 111
         tabs.add(new SimpleViewController(activity, childRegistry, "6", tabOptions));
@@ -393,6 +389,36 @@ public class BottomTabsControllerTest extends BaseTest {
393 389
         verify(tabsAttacher).destroy();
394 390
     }
395 391
 
392
+    private void prepareViewsForTests() {
393
+        perform(uut, ViewController::destroy);
394
+        bottomTabs = spy(new BottomTabs(activity) {
395
+            @Override
396
+            public void superCreateItems() {
397
+
398
+            }
399
+        });
400
+        createChildren();
401
+        tabs = createTabs();
402
+        presenter = spy(new BottomTabsPresenter(tabs, new Options()));
403
+        bottomTabPresenter = spy(new BottomTabPresenter(activity, tabs, ImageLoaderMock.mock(), new Options()));
404
+        tabsAttacher = spy(new BottomTabsAttacher(tabs, presenter));
405
+        uut = createBottomTabs();
406
+
407
+        uut.setParentController(Mockito.mock(ParentController.class));
408
+        CoordinatorLayout parent = new CoordinatorLayout(activity);
409
+        parent.addView(uut.getView());
410
+        activity.setContentView(parent);
411
+    }
412
+
413
+    private void createChildren() {
414
+        child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions));
415
+        child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions));
416
+        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions));
417
+        child4 = spy(createStack());
418
+        child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions));
419
+        when(child5.handleBack(any())).thenReturn(true);
420
+    }
421
+
396 422
     @NonNull
397 423
     private List<ViewController> createTabs() {
398 424
         return Arrays.asList(child1, child2, child3, child4, child5);