I'm trying to make a collapsible tab bar and I think i'm almost there. The only thing that's in my way is the empty space on top of the ScrollView (see GIF). I'm using React Navigation and the MaterialTopTabNavigator. Ideally I would like to use some sort of zIndex to place the tab bar on top of the screen instead of above the screen. I've already tried to change the screens top position to a negative and use the height instead of the top position, but that didn't yield the desired result. I would love to get some inspiration from you guys. :)
const Tab = createMaterialTopTabNavigator();import Tabs from '../components/tabs';const TabNavigator = () => { return (<Tab.Navigator tabBar={(props) => <Tabs {...props} />}><Tab.Screen name="Home" component={Home} /><Tab.Screen name="Spendings" component={Spendings} /></Tab.Navigator> );};
import {MaterialTopTabBarProps} from '@react-navigation/material-top-tabs';import React, {useEffect, useRef, useState} from 'react';import {Animated, DeviceEventEmitter, TouchableOpacity} from 'react-native';const Tabs: React.FunctionComponent<MaterialTopTabBarProps> = (props) => { const tabAnimation = useRef(new Animated.Value(0)).current; const [scrollDirection, setScrollDirection] = useState(''); let offset = 0; useEffect(() => { DeviceEventEmitter.addListener('scrollEmitter', (e) => { moveTabs(e.nativeEvent.contentOffset.y); }); }, []); const moveTabs = (y: number) => { const currentOffset = y; var direction = currentOffset < offset || currentOffset < 70 ? 'up' : currentOffset > offset ? 'down' : 'unclear'; offset = currentOffset; setScrollDirection(direction); }; useEffect(() => { if (scrollDirection == 'up') Animated.spring(tabAnimation, { toValue: 0, useNativeDriver: false, }).start(); else { Animated.spring(tabAnimation, { toValue: -70, useNativeDriver: false, }).start(); } }, [scrollDirection]); return (<Animated.View style={[ { height: 50, flexDirection: 'row', }, {top: tabAnimation}, ]}> {props.state.routes.map((route: any, index: any) => { const {options} = props.descriptors[route.key]; const label = options.tabBarLabel !== undefined ? options.tabBarLabel : options.title !== undefined ? options.title : route.name; const isFocused = props.state.index === index; const onPress = () => { const event = props.navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, }); if (!isFocused && !event.defaultPrevented) { props.navigation.navigate(route.name); } }; const onLongPress = () => { props.navigation.emit({ type: 'tabLongPress', target: route.key, }); }; return (<TouchableOpacity accessibilityRole="button" accessibilityState={isFocused ? {selected: true} : {}} accessibilityLabel={options.tabBarAccessibilityLabel} testID={options.tabBarTestID} onPress={onPress} onLongPress={onLongPress} style={{ flex: 1, backgroundColor: 'lightgrey', margin: 1, alignItems: 'center', justifyContent: 'center', }}><Animated.Text style={{opacity: 1, zIndex: 2}}> {label}</Animated.Text></TouchableOpacity> ); })}</Animated.View> );};export default Tabs;