How to add tabs and show the name of the button in the header of the application?

Viewed 184

How to add submenu or tabs in the upper part in connection with the lower button and show the name of the lower button in the header of the application.

import React from 'react';
import { createStackNavigator } from 'react-navigation-stack';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { createAppContainer } from 'react-navigation';
import { MaterialIcons, MaterialCommunityIcons } from '@expo/vector-icons';

import Splash from '../screens/Splash';
import NewsListScreen from '../screens/NewsListScreen';
import NewsItemScreen from '../screens/NewsItemScreen';


const StackNavigator = createStackNavigator({
    //Splash: {screen: Splash},
    News: {
        screen: NewsListScreen
    },
    NewsItem: {
        screen: NewsItemScreen,
        navigationOptions: {
            headerTitle: 'News Item'
        }
    }
});

const BottomTabNavigator = createBottomTabNavigator({
    Home: {
        screen: StackNavigator,
        navigationOptions: {
            tabBarIcon: () => <MaterialIcons name="home" size={24} />
        }
    },
    News: {
        screen: StackNavigator,
        navigationOptions: {
            tabBarIcon: () => <MaterialCommunityIcons name="newspaper-variant-outline" size={24} />
        }
    }
})

export default createAppContainer(BottomTabNavigator);

What I want to achieve is the following:

enter image description here

As you can see, the bottom button [News] has three referential buttons in the upper part [FEATURED], [RELEVANT], [SEARCH] and, in addition to that, it recovers the name of the bottom button and adds it to the application header below the top buttons.

2 Answers

[EDITED] Your NewsListScreen screen, instead of just being a tab bar component, can be something like that:

function NewsListScreen = (props) => (
  <View>
    <Text>News</Text>
    <TabBarComponent {...props} />
  </View>
)

function TabBarComponent = createMaterialTopTabNavigator({
  featured: ... ,
  relevant: ... ,
  search: ... ,
})

That being said, if you can, you should update your project to react navigation v5, which is I think much more user friendly.

Final Output:

enter image description here

Implementation using react-navigation v5 :

import * as React from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import {
  NavigationContainer,
  useNavigationState,
} from '@react-navigation/native';

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';

const TopTab = createMaterialTopTabNavigator();

const BottomTab = createBottomTabNavigator();

/*
Here I am using MaterialTopTabNavigator instead of StackNavigator,
which is a better choice based on UI snapshot in this case.
*/
function NewsTopTabs() {

/*
in case you want to set the title dynamically then you can use the 
useNavigationState hook but as there are just two bottom tabs so 
I am using hardcoded values.
*/

  const nav = useNavigationState((state) => state);
  return (
    <>
      <View style={styles.titleBar}>
        <Text style={styles.title}>News</Text>
      </View>
      <TopTab.Navigator>
        <TopTab.Screen name="Featured" component={Featured} />
        <TopTab.Screen name="Relevant" component={Relevant} />
        <TopTab.Screen name="Search" component={Search} />
      </TopTab.Navigator>
    </>
  );
}

function MatchesTopTabs() {

  return (
    <>
      <View style={styles.titleBar}>
        <Text style={styles.title}>Matches</Text>
      </View>
      <TopTab.Navigator>
        <TopTab.Screen name="Featured" component={Featured} />
        <TopTab.Screen name="Relevant" component={Relevant} />
        <TopTab.Screen name="Search" component={Search} />
      </TopTab.Navigator>
    </>
  );
}

function MyBottomTabs({ navigation }) {
  return (
    <BottomTab.Navigator>
      <BottomTab.Screen name="News" component={NewsTopTabs} />
      <BottomTab.Screen name="Matches" component={MatchesTopTabs} />
    </BottomTab.Navigator>
  );
}

//[FEATURED], [RELEVANT], [SEARCH]

export default function App() {
  return (
    <NavigationContainer>
      <MyBottomTabs />
    </NavigationContainer>
  );
}

//[FEATURED], [RELEVANT], [SEARCH]
const Featured = () => {
  const nav = useNavigationState((state) => state);
  return (
    <View style={styles.screen}>
      <Text>Featured</Text>
    </View>
  );
};

const Relevant = () => {
  const nav = useNavigationState((state) => state);
  return (
    <View style={styles.screen}>
      <Text>Relevant</Text>
    </View>
  );
};

const Search = () => {
  const nav = useNavigationState((state) => state);
  return (
    <View style={styles.screen}>
      <Text>Search</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  titleBar: {
    height: 50,
    width: Math.round(Dimensions.get('window').width),
    backgroundColor: 'white',
    justifyContent: 'center',
    borderBottomColor: "lightgrey",
    borderBottomWidth: 1,
    paddingLeft: 10,
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
  },
  screen:{
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  }
});

Working Example: Expo Snack

Related