Browse Source

Improved tab bar hiding logic

Arnaud Vergnet 3 years ago
parent
commit
a9caca9969
1 changed files with 59 additions and 30 deletions
  1. 59
    30
      src/components/Tabbar/CustomTabBar.js

+ 59
- 30
src/components/Tabbar/CustomTabBar.js View File

@@ -3,6 +3,7 @@ import {withTheme} from 'react-native-paper';
3 3
 import TabIcon from "./TabIcon";
4 4
 import TabHomeIcon from "./TabHomeIcon";
5 5
 import {Animated} from 'react-native';
6
+import {Collapsible} from "react-navigation-collapsible";
6 7
 
7 8
 type Props = {
8 9
     state: Object,
@@ -24,41 +25,69 @@ const TAB_ICONS = {
24 25
     planex: 'clock',
25 26
 };
26 27
 
27
-/**
28
- * Abstraction layer for Agenda component, using custom configuration
29
- */
30 28
 class CustomTabBar extends React.Component<Props, State> {
31 29
 
32 30
     static TAB_BAR_HEIGHT = 48;
33 31
 
34 32
     state = {
35 33
         translateY: new Animated.Value(0),
36
-        barSynced: false,// Is the bar synced with the header for animations?
37 34
     }
38 35
 
36
+    syncTabBar = (route, index) => {
37
+        const state = this.props.state;
38
+        const isFocused = state.index === index;
39
+        if (isFocused) {
40
+            const stackState = route.state;
41
+            const stackRoute = stackState ? stackState.routes[stackState.index] : undefined;
42
+            const params: { collapsible: Collapsible } = stackRoute ? stackRoute.params : undefined;
43
+            const collapsible = params ? params.collapsible : undefined;
44
+            if (collapsible) {
45
+                this.setState({
46
+                    translateY: Animated.multiply(-1.5, collapsible.translateY), // Hide tab bar faster than header bar
47
+                });
48
+            }
49
+        }
50
+    };
51
+
52
+    /**
53
+     * Navigates to the given route if it is different from the current one
54
+     *
55
+     * @param route Destination route
56
+     * @param currentIndex The current route index
57
+     * @param destIndex The destination route index
58
+     */
39 59
     onItemPress(route: Object, currentIndex: number, destIndex: number) {
40 60
         const event = this.props.navigation.emit({
41 61
             type: 'tabPress',
42 62
             target: route.key,
43 63
             canPreventDefault: true,
44 64
         });
45
-        if (currentIndex !== destIndex && !event.defaultPrevented) {
46
-            this.state.translateY = new Animated.Value(0);
65
+        if (currentIndex !== destIndex && !event.defaultPrevented)
47 66
             this.props.navigation.navigate(route.name);
48
-        }
49 67
     }
50 68
 
69
+    /**
70
+     * Navigates to tetris screen on home button long press
71
+     *
72
+     * @param route
73
+     */
51 74
     onItemLongPress(route: Object) {
52 75
         const event = this.props.navigation.emit({
53 76
             type: 'tabLongPress',
54 77
             target: route.key,
55 78
             canPreventDefault: true,
56 79
         });
57
-        if (route.name === "home" && !event.defaultPrevented) {
80
+        if (route.name === "home" && !event.defaultPrevented)
58 81
             this.props.navigation.navigate('tetris');
59
-        }
60 82
     }
61 83
 
84
+    /**
85
+     * Gets an icon for the given route if it is not the home one as it uses a custom button
86
+     *
87
+     * @param route
88
+     * @param focused
89
+     * @returns {null}
90
+     */
62 91
     tabBarIcon = (route, focused) => {
63 92
         let icon = TAB_ICONS[route.name];
64 93
         icon = focused ? icon : icon + ('-outline');
@@ -68,39 +97,34 @@ class CustomTabBar extends React.Component<Props, State> {
68 97
             return null;
69 98
     };
70 99
 
71
-
100
+    /**
101
+     * Finds the active route and syncs the tab bar animation with the header bar
102
+     */
72 103
     onRouteChange = () => {
73
-        this.setState({barSynced: false});
104
+        this.props.state.routes.map(this.syncTabBar)
74 105
     }
75 106
 
107
+    /**
108
+     * Gets a tab icon render.
109
+     * If the given route is focused, it syncs the tab bar and header bar animations together
110
+     *
111
+     * @param route The route for the icon
112
+     * @param index The index of the current route
113
+     * @returns {*}
114
+     */
76 115
     renderIcon = (route, index) => {
77 116
         const state = this.props.state;
78 117
         const {options} = this.props.descriptors[route.key];
79 118
         const label =
80
-            options.tabBarLabel !== undefined
119
+            options.tabBarLabel != null
81 120
                 ? options.tabBarLabel
82
-                : options.title !== undefined
121
+                : options.title != null
83 122
                 ? options.title
84 123
                 : route.name;
85 124
 
86
-        const isFocused = state.index === index;
87
-
88 125
         const onPress = () => this.onItemPress(route, state.index, index);
89
-
90 126
         const onLongPress = () => this.onItemLongPress(route);
91
-
92
-        if (isFocused) {
93
-            const stackState = route.state;
94
-            const stackRoute = route.state ? stackState.routes[stackState.index] : undefined;
95
-            const params = stackRoute ? stackRoute.params : undefined;
96
-            const collapsible = params ? params.collapsible : undefined;
97
-            if (collapsible && !this.state.barSynced) {
98
-                this.setState({
99
-                    translateY: Animated.multiply(-1.5, collapsible.translateY),
100
-                    barSynced: true,
101
-                });
102
-            }
103
-        }
127
+        const isFocused = state.index === index;
104 128
 
105 129
         const color = isFocused ? this.props.theme.colors.primary : this.props.theme.colors.tabIcon;
106 130
         if (route.name !== "home") {
@@ -124,8 +148,13 @@ class CustomTabBar extends React.Component<Props, State> {
124 148
             />
125 149
     };
126 150
 
151
+    getIcons() {
152
+        return this.props.state.routes.map(this.renderIcon);
153
+    }
154
+
127 155
     render() {
128 156
         this.props.navigation.addListener('state', this.onRouteChange);
157
+        const icons = this.getIcons();
129 158
         return (
130 159
             <Animated.View
131 160
                 useNativeDriver
@@ -140,7 +169,7 @@ class CustomTabBar extends React.Component<Props, State> {
140 169
                     transform: [{translateY: this.state.translateY}],
141 170
                 }}
142 171
             >
143
-                {this.props.state.routes.map(this.renderIcon)}
172
+                {icons}
144 173
             </Animated.View>
145 174
         );
146 175
     }

Loading…
Cancel
Save