2

I'm using react navigation v5. I am using the bottom tab navigator. I want to add a border to the top of the active tab. So far everything I've tried has not worked. Here is my navigation file (minus the imports):

const AuthStack = createStackNavigator()
const InfoStack = createStackNavigator()
const PhotoStack = createStackNavigator()
const ProfitStack = createStackNavigator()
const RehabStack = createStackNavigator()
const DrawerNav = createDrawerNavigator()
const TabNav = createBottomTabNavigator()

const createAuthStack = () => (
   <AuthStack.Navigator>
      <AuthStack.Screen name='Sign Up' component={SignUpScreen} />
      <AuthStack.Screen name='Sign In' component={SignInScreen} />
   </AuthStack.Navigator>
)

const stackOptions = {
   headerStyle: {
      backgroundColor: colors.colorGrayLight,
        borderBottomColor: colors.colorPrimary,
        borderBottomWidth: 2
   },
    
}

const createInfoStack = () => (
   <InfoStack.Navigator screenOptions={stackOptions}>
      <InfoStack.Screen name='Info Stack' component={PropertyInfoScreen} />
   </InfoStack.Navigator>
)

const createProfitStack = () => (
   <ProfitStack.Navigator screenOptions={stackOptions}>
      <PhotoStack.Screen name='Profit Stack' component={ProfitCalculatorScreen} />
   </ProfitStack.Navigator>
)

const createRehabStack = () => (
   <RehabStack.Navigator screenOptions={stackOptions}>
      <RehabStack.Screen name='Rehab Stack' component={RehabCostsScreen} />
   </RehabStack.Navigator>
)

const createPhotosStack = () => (
   <PhotoStack.Navigator screenOptions={stackOptions}>
      <PhotoStack.Screen name='Photo Stack' component={PropertyPhotosScreen} />
   </PhotoStack.Navigator>
)

const createScreenOptions = ({ focused, color, route }) => {
   let imgSrc

   switch (route.name.toLowerCase()) {
      case 'info':
         imgSrc = images.iconPropertyInfo
         break
      case 'profit':
         imgSrc = images.iconProfit
         break
      case 'rehab':
         imgSrc = images.iconRehab
         break
        case 'photos':
            imgSrc = images.iconPhotos 
            break
   }

   return {
      tabBarIcon: ({ focused, color }) => (
         <View style={{ alignItems: 'center', marginTop: 10 }}>
            <Image
               source={imgSrc}
               resizeMode='contain'
               style={{
                  width: 25,
                  height: 25,
                  tintColor: color,
               }}
            />
            <Text style={{ color: color, fontSize: 12 }}>{route.name}</Text>
         </View>
      ),

       tabBarButton: (props) => {
         return (
            <TabBarButton {...props} />
         )
       }
   }
}

const createTabNav = ({ route, navigation}) => {
   const focusedRoute = getFocusedRouteNameFromRoute(route)

   return (
      <TabNav.Navigator
         tabBarOptions={{
            activeTintColor: colors.colorPrimary,
            inactiveTintColor: colors.colorCharcoal,
            keyboardHidesTabBar: true,
            allowFontScaling: false,
            style: {
               backgroundColor: colors.colorGrayLight,
            },
            labelStyle: {
               fontSize: 12,
            },
            showLabel: false,
         }}>
         <TabNav.Screen name='Info' component={createInfoStack} options={createScreenOptions}/>
         <TabNav.Screen name='Profit' component={createProfitStack} options={createScreenOptions} />
         <TabNav.Screen name='Rehab' component={createRehabStack} options={createScreenOptions} />
         <TabNav.Screen name='Photos' component={createPhotosStack} options={createScreenOptions} />
      </TabNav.Navigator>
   )
}

export default MainNav = () => {
   const [isAuthenticated, setIsAuthenticated] = useState(false)

   return (
      <NavigationContainer>
         <DrawerNav.Navigator>
            <DrawerNav.Screen name='Main' component={createTabNav} />
         </DrawerNav.Navigator>
      </NavigationContainer>
   )
}

I attempted to create my own custom tabIcon / tabBarButton but I don't know how to pass in to the tabBarButton if the tab is active or not. The props "focused" or "navigation" are not passed into the tabBarButton function. I want my bottom nav to look like the picture here

enter image description here

Jo Momma
  • 1,126
  • 15
  • 31
  • 1
    Here is the same functionality that you need, you just need to change the code for bottom border to top border: https://stackoverflow.com/questions/67088747/how-to-add-an-indicator-under-the-active-bottom-tab – Dipan Sharma May 17 '21 at 04:32
  • @DipanSharma You were right. I guess I should have asked the question differently. I didn't find that solution on here when I was searching. Thank you so much! – Jo Momma May 17 '21 at 13:48

2 Answers2

3

You can make use of focused prop like this

<Tab.Screen
        name="ScreenName"
        component={Screen}
        options={{
          tabBarIcon: ({ color, focused }) => (
            <View style={styles.individualTabWrapper}>
              {
                focused && <View style={styles.activeDot} />
              }
              <CustomIcon name={'home'} size={focused ? 27 : 25} color={color} />
            </View>
          ),
         
          tabBarLabel: ({ focused, color }) => (
            <>
              <Text style={[styles.label, { color: 'black'}]}>Home</Text>
            </>
          )
        }}
      />
Sjonchhe
  • 790
  • 8
  • 16
  • 1
    Thank you for your contribution. I used a similar approach that was suggested by @DipanSharma in the comments section. However, I like this approach too because it allows me to easily animate the tab indicator too. I may switch to this implementation. Credit given. Thanks bro – Jo Momma May 17 '21 at 14:03
3

Here is my solution, you can set your border as you wish.

const Tab = createBottomTabNavigator()

const TAB_ICON = {
    Meals: "fast-food",
    Favorites: "star"
}

const activeTab = (focused,size,color,iconName) => {
    return (
        focused? (
        <View style={{ borderTopWidth:2, width: "100%", height: "100%", borderColor: Colors.ui.primary }}>
            <Ionicons style={{ alignSelf: "center", justifyContent: "center", alignItems: "center" }} name={iconName} size={size} color={color} />
        </View>) :
        (
            <Ionicons name={iconName} size={size} color={color} />
        )
    )
}

const iconOptions = ({ route }) => {
    const iconName = TAB_ICON[route.name];
    return {
        tabBarIcon: ({ focused, size, color }) => (
            size = focused ? 24 : 20,
            activeTab(focused,size,color,iconName)
        ),
        tabBarActiveTintColor: Colors.ui.primary,
        tabBarInactiveTintColor: Colors.ui.secondary,
        tabBarStyle: { backgroundColor: Colors.bg.secondary },
    }
}

export const TabNavigator = () => {
    return (
        <NavigationContainer>
            <Tab.Navigator
                screenOptions={iconOptions}
            >
                <Tab.Screen name="Meals" component={MealsNavigator} options={{ headerShown: false, title: "MEALS" }}></Tab.Screen>
                <Tab.Screen name="Favorites" component={FavoritesScreen} options={{ headerTitleAlign: "center", title: "FAVORITES", tabBarIconStyle: ({ focused }) => (borderTopWidth = 2, borderColor = "black") }}></Tab.Screen>
            </Tab.Navigator>
        </NavigationContainer>
    )
}
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 22 '22 at 15:43