Browse Source

Android: Set bottom tabs layout over tabs content

Amit Davidi 7 years ago
parent
commit
d1e31ee437

+ 7
- 7
android/app/deprecated/java/com/reactnativenavigation/utils/ViewUtils.java View File

@@ -57,6 +57,13 @@ public class ViewUtils {
57 57
         return pixels * scaledDensity;
58 58
     }
59 59
 
60
+    public static float getScreenHeight() {
61
+        WindowManager wm = (WindowManager) NavigationApplication.instance.getSystemService(Context.WINDOW_SERVICE);
62
+        DisplayMetrics metrics = new DisplayMetrics();
63
+        wm.getDefaultDisplay().getMetrics(metrics);
64
+        return metrics.heightPixels;
65
+    }
66
+
60 67
     public static int generateViewId() {
61 68
         if (Build.VERSION.SDK_INT >= 17) {
62 69
             return View.generateViewId();
@@ -65,13 +72,6 @@ public class ViewUtils {
65 72
         }
66 73
     }
67 74
 
68
-    public static float getScreenHeight() {
69
-        WindowManager wm = (WindowManager) NavigationApplication.instance.getSystemService(Context.WINDOW_SERVICE);
70
-        DisplayMetrics metrics = new DisplayMetrics();
71
-        wm.getDefaultDisplay().getMetrics(metrics);
72
-        return metrics.heightPixels;
73
-    }
74
-
75 75
     private static int compatGenerateViewId() {
76 76
         for (; ; ) {
77 77
             final int result = viewId.get();

+ 39
- 3
android/app/src/main/java/com/reactnativenavigation/layout/bottomtabs/BottomTabs.java View File

@@ -1,25 +1,61 @@
1 1
 package com.reactnativenavigation.layout.bottomtabs;
2 2
 
3
+import android.graphics.Color;
4
+import android.os.Build;
3 5
 import android.support.design.widget.BottomNavigationView;
6
+import android.view.View;
7
+import android.view.ViewGroup;
4 8
 import android.widget.RelativeLayout;
9
+import android.widget.RelativeLayout.LayoutParams;
10
+
11
+import java.util.concurrent.atomic.AtomicInteger;
5 12
 
6 13
 import static android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM;
7 14
 
8 15
 public class BottomTabs {
9 16
 
17
+    private static final AtomicInteger viewId = new AtomicInteger(1);
18
+
10 19
     private BottomNavigationView bottomNavigationView;
11 20
 
12 21
     public void attach(RelativeLayout parentLayout) {
13 22
         bottomNavigationView = new BottomNavigationView(parentLayout.getContext());
23
+        bottomNavigationView.setId(generateViewId());
24
+        bottomNavigationView.setBackgroundColor(Color.DKGRAY);
14 25
 
15
-        RelativeLayout.LayoutParams lp =
16
-                new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
26
+        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
17 27
         lp.addRule(ALIGN_PARENT_BOTTOM);
18 28
         bottomNavigationView.setLayoutParams(lp);
19 29
         parentLayout.addView(bottomNavigationView, lp);
20 30
     }
21 31
 
22
-    public void addTab(String label) {
32
+    public void addTab(String label, View tabContent) {
23 33
         bottomNavigationView.getMenu().add(label);
34
+
35
+        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
36
+        params.addRule(RelativeLayout.ABOVE, bottomNavigationView.getId());
37
+
38
+        ViewGroup parent = (ViewGroup) bottomNavigationView.getParent();
39
+        parent.addView(tabContent, params);
40
+    }
41
+
42
+    private int generateViewId() {
43
+        if (Build.VERSION.SDK_INT >= 17) {
44
+            return View.generateViewId();
45
+        } else {
46
+            return compatGenerateViewId();
47
+        }
48
+    }
49
+
50
+    private int compatGenerateViewId() {
51
+        while(true) {
52
+            final int result = viewId.get();
53
+            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
54
+            int newValue = result + 1;
55
+            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
56
+            if (viewId.compareAndSet(result, newValue)) {
57
+                return result;
58
+            }
59
+        }
24 60
     }
25 61
 }

+ 2
- 5
android/app/src/main/java/com/reactnativenavigation/layout/bottomtabs/BottomTabsContainer.java View File

@@ -13,11 +13,8 @@ public class BottomTabsContainer extends RelativeLayout {
13 13
         createBottomTabs(bottomTabsCreator);
14 14
     }
15 15
 
16
-    public void setTabContent(View tab) {
17
-        bottomTabs.addTab("#0");
18
-
19
-        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
20
-        addView(tab, lp);
16
+    public void setTabContent(View tabContent) {
17
+        bottomTabs.addTab("#0", tabContent);
21 18
     }
22 19
 
23 20
     private void createBottomTabs(BottomTabsCreator bottomTabsCreator) {

+ 21
- 12
android/app/src/test/java/com/reactnativenavigation/LayoutFactoryTest.java View File

@@ -5,12 +5,12 @@ import android.support.v7.app.AppCompatActivity;
5 5
 import android.view.View;
6 6
 import android.view.ViewGroup;
7 7
 
8
-import com.reactnativenavigation.layout.bottomtabs.BottomTabs;
9
-import com.reactnativenavigation.layout.bottomtabs.BottomTabsContainer;
10 8
 import com.reactnativenavigation.layout.Container;
11 9
 import com.reactnativenavigation.layout.ContainerStack;
12 10
 import com.reactnativenavigation.layout.LayoutFactory;
13 11
 import com.reactnativenavigation.layout.LayoutNode;
12
+import com.reactnativenavigation.layout.bottomtabs.BottomTabs;
13
+import com.reactnativenavigation.layout.bottomtabs.BottomTabsContainer;
14 14
 import com.reactnativenavigation.layout.bottomtabs.BottomTabsCreator;
15 15
 
16 16
 import org.junit.Before;
@@ -26,8 +26,11 @@ import java.util.HashMap;
26 26
 import java.util.List;
27 27
 
28 28
 import static org.assertj.core.api.Java6Assertions.assertThat;
29
+import static org.mockito.ArgumentMatchers.any;
30
+import static org.mockito.ArgumentMatchers.anyString;
29 31
 import static org.mockito.ArgumentMatchers.eq;
30 32
 import static org.mockito.Mockito.mock;
33
+import static org.mockito.Mockito.verify;
31 34
 import static org.mockito.Mockito.when;
32 35
 
33 36
 @RunWith(RobolectricTestRunner.class)
@@ -62,7 +65,7 @@ public class LayoutFactoryTest {
62 65
     }
63 66
 
64 67
     @Test
65
-    public void returnsContainerStack() throws Exception  {
68
+    public void returnsContainerStack() throws Exception {
66 69
         when(rootViewCreator.createRootView(eq(VIEW_ID), eq(VIEW_NAME))).thenReturn(mockView);
67 70
         final LayoutNode containerNode = createContainerNode();
68 71
         final LayoutNode stackNode = getContainerStackNode(containerNode);
@@ -75,7 +78,7 @@ public class LayoutFactoryTest {
75 78
     }
76 79
 
77 80
     @Test
78
-    public void returnsContainerStackWithMultipleViews() throws Exception  {
81
+    public void returnsContainerStackWithMultipleViews() throws Exception {
79 82
         final View mockView1 = mock(View.class);
80 83
         final View mockView2 = mock(View.class);
81 84
         when(rootViewCreator.createRootView(eq(VIEW_ID), eq(VIEW_NAME))).thenReturn(mockView1);
@@ -97,20 +100,19 @@ public class LayoutFactoryTest {
97 100
 
98 101
     @Test
99 102
     public void returnsSingleTabContent() throws Exception {
103
+        BottomTabs bottomTabsMock = mock(BottomTabs.class);
100 104
         when(rootViewCreator.createRootView(eq(VIEW_ID), eq(VIEW_NAME))).thenReturn(mockView);
101 105
         final LayoutNode containerNode = createContainerNode();
102 106
         final LayoutNode tabNode = createTabNode(containerNode);
103 107
 
104
-        final View result = createLayoutFactory().create(tabNode);
108
+        final View result = createLayoutFactory(bottomTabsMock).create(tabNode);
105 109
 
106 110
         assertThat(result).isInstanceOf(BottomTabsContainer.class);
107
-        View containerView = assertViewChildrenCount((BottomTabsContainer) result, 1).get(0);
108
-        assertThat(containerView).isInstanceOf(Container.class);
109
-        assertViewChildren((Container) containerView, mockView);
111
+        verify(bottomTabsMock).addTab(eq("#0"), any(Container.class));
110 112
     }
111 113
 
112 114
     @Test(expected = IllegalArgumentException.class)
113
-    public void throwsExceptionForUnknownType() throws Exception  {
115
+    public void throwsExceptionForUnknownType() throws Exception {
114 116
         when(rootViewCreator.createRootView(eq(VIEW_ID), eq(VIEW_NAME))).thenReturn(mockView);
115 117
         final LayoutNode node = new LayoutNode(VIEW_ID, "***unknownType***", Collections.<String, Object>emptyMap());
116 118
 
@@ -118,9 +120,16 @@ public class LayoutFactoryTest {
118 120
     }
119 121
 
120 122
     private LayoutFactory createLayoutFactory() {
121
-        BottomTabs bottomTabs = mock(BottomTabs.class);
122
-        BottomTabsCreator bottomTabsCreator = mock(BottomTabsCreator.class);
123
-        when(bottomTabsCreator.create()).thenReturn(bottomTabs);
123
+        return createLayoutFactory(null);
124
+    }
125
+
126
+    private LayoutFactory createLayoutFactory(BottomTabs bottomTabs) {
127
+        BottomTabsCreator bottomTabsCreator = null;
128
+        if (bottomTabs != null) {
129
+            bottomTabsCreator = mock(BottomTabsCreator.class);
130
+            when(bottomTabsCreator.create()).thenReturn(bottomTabs);
131
+        }
132
+
124 133
         return new LayoutFactory(activity, rootViewCreator, bottomTabsCreator);
125 134
     }
126 135