react-nativereact-native-navigationreact-navigation-bottom-tab

React Native How to show an element above bottom tab navigator


I am trying to show a media player above the bottom tab navigator just like in spotify app. It should stay there in same state across all the screens (bottom tabs).

enter image description here

Any suggestions or approaches to implement this in React native ?


Solution

  • I would suggest to use an React.Context as you wanna show the same object (music control panel) on each screen with same state and not an replica on each screen.

    For positioning I suggest using an absolute position. This works together with "react-navigation" because header and bottom areas are changed. This means bottom:0 is no longer the screens bottom within a tab navigator it's right above the TabBar.

    Here is an example:

    import * as React from 'react';
    import { Text, View } from 'react-native';
    import { NavigationContainer } from '@react-navigation/native';
    import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
    import { MusicControlPanelContext, MusicControlPanelConsumer } from './components/MusicControlContext';
    import {MusicControlPanel} from './components/MusicContorlPanel'
    
    function HomeScreen() {
      return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Text>Home!</Text>
          <MusicControlPanelConsumer/>
        </View>
      );
    }
    
    function SettingsScreen() {
      return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Text>Settings!</Text>
          <MusicControlPanelConsumer/>
        </View>
      );
    }
    
    const Tab = createBottomTabNavigator();
    
    export default function App() {
      return (
        <MusicControlPanelContext.Provider value={MusicControlPanel}>
          <>
            <NavigationContainer>
              <Tab.Navigator
                tabBarOptions={{
                  activeTintColor: '#000000',
                  inactiveTintColor: 'gray',
                  activeBackgroundColor: '#ff0000',
                  inactiveBackgroundColor: '#ff0000',
                  style: {
                    backgroundColor: '#ffffff',
                  },
                }}>
                <Tab.Screen name="Home" component={HomeScreen} />
                <Tab.Screen name="Settings" component={SettingsScreen} />
              </Tab.Navigator>
            </NavigationContainer>
          </>
        </MusicControlPanelContext.Provider>
      );
    }
    
    
    import * as React from 'react';
    import { MusicControlPanelContext } from './MusicControlPanelContext';
    import { View } from 'react-native';
    
    function MusicControlPanelConsumer() {
      return (
       
        <MusicControlPanelContext.Consumer>
          {(Component) => <Component/>}
        </MusicControlPanelContext.Consumer>
        
      );
    }
    
    export { MusicControlPanelConsumer };
    
    
    import * as React from 'react';
    import {MusicControlPanel} from '../MusicContorlPanel'
    
    export const MusicControlPanelContext = React.createContext<React.FC>(MusicControlPanel);
    
    
    import * as React from 'react';
    import { View, Text, Pressable } from 'react-native';
    
    export const MusicControlPanel: React.FC = () => {
      const [startStop, setStartStop] = React.useState(false);
      return (
        <View
          style={{
            position: 'absolute',
            width: '90%',
            height: 100,
            backgroundColor: '#ff00ff',
            bottom: 10,
            justifyContent: 'center',
            alignItems: 'center'
          }}>
          <Pressable
            onPress={() =>
              setStartStop((val) => {
                return !val;
              })
            }>
            <Text>{startStop ? 'Start' : 'Stop'}</Text>
          </Pressable>
        </View>
      );
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>