Преглед на файлове

Android: Support tab switching

Amit Davidi преди 8 години
родител
ревизия
ff8da1a3eb

+ 6
- 1
android/app/src/main/java/com/reactnativenavigation/layout/LayoutFactory.java Целия файл

@@ -9,6 +9,7 @@ import com.reactnativenavigation.layout.bottomtabs.BottomTabsCreator;
9 9
 import java.util.List;
10 10
 
11 11
 public class LayoutFactory {
12
+
12 13
     public interface RootViewCreator {
13 14
         View createRootView(String id, String name);
14 15
     }
@@ -49,7 +50,11 @@ public class LayoutFactory {
49 50
 
50 51
     private View createBottomTabs(LayoutNode node) {
51 52
         final BottomTabsContainer tabsContainer = new BottomTabsContainer(activity, bottomTabsCreator);
52
-        tabsContainer.setTabContent(create(node.children.get(0)));
53
+
54
+        for (LayoutNode child : node.children) {
55
+            final View tabContent = create(child);
56
+            tabsContainer.addTabContent(tabContent);
57
+        }
53 58
         return tabsContainer;
54 59
     }
55 60
 

+ 65
- 6
android/app/src/main/java/com/reactnativenavigation/layout/bottomtabs/BottomTabs.java Целия файл

@@ -2,36 +2,83 @@ package com.reactnativenavigation.layout.bottomtabs;
2 2
 
3 3
 import android.graphics.Color;
4 4
 import android.os.Build;
5
+import android.support.annotation.NonNull;
5 6
 import android.support.design.widget.BottomNavigationView;
7
+import android.view.Menu;
8
+import android.view.MenuItem;
6 9
 import android.view.View;
7 10
 import android.view.ViewGroup;
8 11
 import android.widget.RelativeLayout;
9 12
 import android.widget.RelativeLayout.LayoutParams;
10 13
 
14
+import java.util.ArrayList;
15
+import java.util.List;
11 16
 import java.util.concurrent.atomic.AtomicInteger;
12 17
 
13 18
 import static android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM;
14 19
 
15
-public class BottomTabs {
20
+public class BottomTabs implements BottomNavigationView.OnNavigationItemSelectedListener {
16 21
 
17 22
     private static final AtomicInteger viewId = new AtomicInteger(1);
18 23
 
19 24
     private BottomNavigationView bottomNavigationView;
25
+    private List<View> tabsContent;
26
+    private int currentTabId;
20 27
 
21 28
     public void attach(RelativeLayout parentLayout) {
22
-        bottomNavigationView = new BottomNavigationView(parentLayout.getContext());
23
-        bottomNavigationView.setId(generateViewId());
24
-        bottomNavigationView.setBackgroundColor(Color.DKGRAY);
29
+        createBottomNavigation(parentLayout);
30
+        addButtomNavigationToParent(parentLayout);
31
+        bottomNavigationView.setOnNavigationItemSelectedListener(this);
32
+        tabsContent = new ArrayList<>(bottomNavigationView.getMaxItemCount());
33
+    }
25 34
 
35
+    public void addTab(String label, View tabContent) {
36
+        int tabId = getTabsCount();
37
+        bottomNavigationView.getMenu().add(0, tabId, Menu.NONE, label);
38
+
39
+        attachTabContent(tabContent);
40
+        tabsContent.add(tabContent);
41
+
42
+        if (isFirstTabEver()) {
43
+            currentTabId = 0;
44
+            showCurrentTab();
45
+        } else {
46
+            hideTab(tabId);
47
+        }
48
+    }
49
+
50
+    public int getTabsCount() {
51
+        return bottomNavigationView.getMenu().size();
52
+    }
53
+
54
+    @Override
55
+    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
56
+        final int id = item.getItemId();
57
+
58
+        hideCurrentTab();
59
+        currentTabId = id;
60
+        showCurrentTab();
61
+        return true;
62
+    }
63
+
64
+    private void addButtomNavigationToParent(RelativeLayout parentLayout) {
26 65
         LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
27 66
         lp.addRule(ALIGN_PARENT_BOTTOM);
28 67
         bottomNavigationView.setLayoutParams(lp);
29 68
         parentLayout.addView(bottomNavigationView, lp);
30 69
     }
31 70
 
32
-    public void addTab(String label, View tabContent) {
33
-        bottomNavigationView.getMenu().add(label);
71
+    private void createBottomNavigation(RelativeLayout parentLayout) {
72
+        bottomNavigationView = new BottomNavigationView(parentLayout.getContext());
73
+        bottomNavigationView.setId(generateViewId());
74
+        bottomNavigationView.setBackgroundColor(Color.DKGRAY);
75
+    }
76
+
77
+    private boolean isFirstTabEver() {
78
+        return bottomNavigationView.getMenu().size() == 1;
79
+    }
34 80
 
81
+    private void attachTabContent(View tabContent) {
35 82
         LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
36 83
         params.addRule(RelativeLayout.ABOVE, bottomNavigationView.getId());
37 84
 
@@ -39,6 +86,18 @@ public class BottomTabs {
39 86
         parent.addView(tabContent, params);
40 87
     }
41 88
 
89
+    private void showCurrentTab() {
90
+        tabsContent.get(currentTabId).setVisibility(View.VISIBLE);
91
+    }
92
+
93
+    private void hideCurrentTab() {
94
+        hideTab(currentTabId);
95
+    }
96
+
97
+    private void hideTab(int tabId) {
98
+        tabsContent.get(tabId).setVisibility(View.GONE);
99
+    }
100
+
42 101
     private int generateViewId() {
43 102
         if (Build.VERSION.SDK_INT >= 17) {
44 103
             return View.generateViewId();

+ 2
- 2
android/app/src/main/java/com/reactnativenavigation/layout/bottomtabs/BottomTabsContainer.java Целия файл

@@ -13,8 +13,8 @@ public class BottomTabsContainer extends RelativeLayout {
13 13
         createBottomTabs(bottomTabsCreator);
14 14
     }
15 15
 
16
-    public void setTabContent(View tabContent) {
17
-        bottomTabs.addTab("#0", tabContent);
16
+    public void addTabContent(View tabContent) {
17
+        bottomTabs.addTab("#" + bottomTabs.getTabsCount(), tabContent);
18 18
     }
19 19
 
20 20
     private void createBottomTabs(BottomTabsCreator bottomTabsCreator) {

+ 35
- 10
android/app/src/test/java/com/reactnativenavigation/LayoutFactoryTest.java Целия файл

@@ -16,6 +16,7 @@ import com.reactnativenavigation.layout.bottomtabs.BottomTabsCreator;
16 16
 import org.junit.Before;
17 17
 import org.junit.Test;
18 18
 import org.junit.runner.RunWith;
19
+import org.mockito.ArgumentCaptor;
19 20
 import org.robolectric.Robolectric;
20 21
 import org.robolectric.RobolectricTestRunner;
21 22
 
@@ -27,7 +28,6 @@ import java.util.List;
27 28
 
28 29
 import static org.assertj.core.api.Java6Assertions.assertThat;
29 30
 import static org.mockito.ArgumentMatchers.any;
30
-import static org.mockito.ArgumentMatchers.anyString;
31 31
 import static org.mockito.ArgumentMatchers.eq;
32 32
 import static org.mockito.Mockito.mock;
33 33
 import static org.mockito.Mockito.verify;
@@ -44,12 +44,14 @@ public class LayoutFactoryTest {
44 44
 
45 45
     private Activity activity;
46 46
     private View mockView;
47
+    private View otherMockView;
47 48
     private LayoutFactory.RootViewCreator rootViewCreator;
48 49
 
49 50
     @Before
50 51
     public void setUp() {
51 52
         activity = Robolectric.buildActivity(AppCompatActivity.class).get();
52 53
         mockView = new View(activity);
54
+        otherMockView = new View(activity);
53 55
         rootViewCreator = mock(LayoutFactory.RootViewCreator.class);
54 56
     }
55 57
 
@@ -68,7 +70,7 @@ public class LayoutFactoryTest {
68 70
     public void returnsContainerStack() throws Exception {
69 71
         when(rootViewCreator.createRootView(eq(VIEW_ID), eq(VIEW_NAME))).thenReturn(mockView);
70 72
         final LayoutNode containerNode = createContainerNode();
71
-        final LayoutNode stackNode = getContainerStackNode(containerNode);
73
+        final LayoutNode stackNode = createContainerStackNode(containerNode);
72 74
 
73 75
         final ViewGroup result = (ViewGroup) createLayoutFactory().create(stackNode);
74 76
 
@@ -86,7 +88,7 @@ public class LayoutFactoryTest {
86 88
 
87 89
         final LayoutNode containerNode1 = createContainerNode(VIEW_ID, VIEW_NAME);
88 90
         final LayoutNode containerNode2 = createContainerNode(OTHER_VIEW_ID, OTHER_VIEW_NAME);
89
-        final LayoutNode stackNode = getContainerStackNode(Arrays.asList(containerNode1, containerNode2));
91
+        final LayoutNode stackNode = createContainerStackNode(containerNode1, containerNode2);
90 92
 
91 93
         final ViewGroup result = (ViewGroup) createLayoutFactory().create(stackNode);
92 94
 
@@ -101,14 +103,41 @@ public class LayoutFactoryTest {
101 103
     @Test
102 104
     public void returnsSingleTabContent() throws Exception {
103 105
         BottomTabs bottomTabsMock = mock(BottomTabs.class);
106
+        when(bottomTabsMock.getTabsCount()).thenReturn(0);
107
+
104 108
         when(rootViewCreator.createRootView(eq(VIEW_ID), eq(VIEW_NAME))).thenReturn(mockView);
105 109
         final LayoutNode containerNode = createContainerNode();
106 110
         final LayoutNode tabNode = createTabNode(containerNode);
107 111
 
108 112
         final View result = createLayoutFactory(bottomTabsMock).create(tabNode);
109 113
 
114
+        assertThat(result).isInstanceOf(BottomTabsContainer.class);
115
+
116
+        ArgumentCaptor<Container> containerCaptor = ArgumentCaptor.forClass(Container.class);
117
+        verify(bottomTabsMock).addTab(eq("#0"), containerCaptor.capture());
118
+        Container container = containerCaptor.getValue();
119
+        View view = assertViewChildrenCount(container, 1).get(0);
120
+        assertThat(view).isEqualTo(mockView);
121
+    }
122
+
123
+    @Test
124
+    public void returnsTwoTabContent() throws Exception {
125
+        BottomTabs bottomTabsMock = mock(BottomTabs.class);
126
+        when(bottomTabsMock.getTabsCount()).thenReturn(0, 1);
127
+
128
+        when(rootViewCreator.createRootView(eq(VIEW_ID), eq(VIEW_NAME))).thenReturn(mockView);
129
+        final LayoutNode firstTabRootNode = createContainerNode(VIEW_ID, VIEW_NAME);
130
+
131
+        when(rootViewCreator.createRootView(eq(OTHER_VIEW_ID), eq(OTHER_VIEW_NAME))).thenReturn(otherMockView);
132
+        final LayoutNode secondTabRootNode = createContainerStackNode(createContainerNode(OTHER_VIEW_ID, OTHER_VIEW_NAME));
133
+
134
+        final LayoutNode tabNode = createTabNode(firstTabRootNode, secondTabRootNode);
135
+
136
+        final View result = createLayoutFactory(bottomTabsMock).create(tabNode);
137
+
110 138
         assertThat(result).isInstanceOf(BottomTabsContainer.class);
111 139
         verify(bottomTabsMock).addTab(eq("#0"), any(Container.class));
140
+        verify(bottomTabsMock).addTab(eq("#1"), any(ContainerStack.class));
112 141
     }
113 142
 
114 143
     @Test(expected = IllegalArgumentException.class)
@@ -141,18 +170,14 @@ public class LayoutFactoryTest {
141 170
         return new LayoutNode(id, "Container", new HashMap<String, Object>() {{ put("name", name); }});
142 171
     }
143 172
 
144
-    private LayoutNode getContainerStackNode(LayoutNode innerNode) {
145
-        return getContainerStackNode(Arrays.asList(innerNode));
146
-    }
147
-
148
-    private LayoutNode getContainerStackNode(List<LayoutNode> children) {
173
+    private LayoutNode createContainerStackNode(LayoutNode... children) {
149 174
         LayoutNode node = new LayoutNode();
150 175
         node.type = "ContainerStack";
151
-        node.children = children;
176
+        node.children = Arrays.asList(children);
152 177
         return node;
153 178
     }
154 179
 
155
-    private LayoutNode createTabNode(LayoutNode children) {
180
+    private LayoutNode createTabNode(LayoutNode... children) {
156 181
         LayoutNode node = new LayoutNode();
157 182
         node.type = "BottomTabs";
158 183
         node.children = Arrays.asList(children);