1

Using @react-navigation/material-bottom-tabs and following this doc

I wonder how can I remove this weird white round behind the active tab icon?

enter image description here

Its been 2hours I am trying everything. I am missing something

(nb: I am using the same code of the exemple in the doc, if you want to reproduce, with react-native 0.70.6, I had not this problem on the v 0.68.1 )

EDIT: also with shifting={true} when I click on the tab: enter image description here

BenoHiT
  • 203
  • 3
  • 11
  • 1
    Even if you're using the exact same code as the doc, please paste the code you're using - if the docs change, the question might be impossible to reproduce. – Abe Jan 05 '23 at 03:05

2 Answers2

7

To "remove" the tab icon, we can set its color to transparent. However, there is no direct way to manipulate the tab icon's color within @react-navigation/material-bottom-tabs.

@react-navigation/material-bottom-tabs is a wrapper of BottomNavigation in react-native-paper. Thus, the issue is with react-native-paper. This SO question addresses the exact problem. We need to make changes to the theme, where the tab icon's color can be controlled.

However, according to the doc, theme from react-native-paper cannot be directly applied to react navigation. We have to use Provider from react-native-paper and apply the theme to the Provider.

See the sample code and effect below.

enter image description here

import * as React from 'react';
import {Text, View} from 'react-native';
import {
  NavigationContainer,
  useNavigationContainerRef,
} from '@react-navigation/native';
import {createMaterialBottomTabNavigator} from '@react-navigation/material-bottom-tabs';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import {DefaultTheme, Provider} from 'react-native-paper';

const Tab = createMaterialBottomTabNavigator();

function HomeScreen() {
  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Home!</Text>
    </View>
  );
}

function ProfileScreen() {
  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Profile!</Text>
    </View>
  );
}

function SettingsScreen() {
  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Settings!</Text>
    </View>
  );
}

const App = () => {
  const barColors = {
    home: 'aqua',
    settings: 'gold',
    profile: 'lawngreen',
  };

  const [tab, setTab] = React.useState<keyof typeof barColors>('home');
  const navRef = useNavigationContainerRef();

  React.useEffect(() => {
    const unsubscribe = navRef.addListener('state', () => {
      const currRoute = navRef.getCurrentRoute();
      if (currRoute) {
        // A work-around to set background color for the bar after the ripple
        // effect completes. The 200 ms delay comes from trial and error
        setTimeout(() => setTab(currRoute.name as keyof typeof barColors), 200);
      }
    });
    return unsubscribe;
  });

  return (
    <NavigationContainer ref={navRef}>
      <Tab.Navigator
        initialRouteName="home"
        shifting={true}
        activeColor="#e91e63"
        barStyle={{
          backgroundColor: barColors[tab],
        }}>
        <Tab.Screen
          name="home"
          component={HomeScreen}
          options={{
            tabBarColor: barColors.home,
            tabBarLabel: 'Home',
            tabBarIcon: ({color}) => (
              <MaterialCommunityIcons name="home" color={color} size={26} />
            ),
          }}
        />
        <Tab.Screen
          name="settings"
          component={SettingsScreen}
          options={{
            tabBarColor: barColors.settings,
            tabBarLabel: 'Settings',
            tabBarIcon: ({color}) => (
              <MaterialCommunityIcons name="cog" color={color} size={26} />
            ),
          }}
        />
        <Tab.Screen
          name="profile"
          component={ProfileScreen}
          options={{
            tabBarColor: barColors.profile,
            tabBarLabel: 'Profile',
            tabBarIcon: ({color}) => (
              <MaterialCommunityIcons name="account" color={color} size={26} />
            ),
          }}
        />
      </Tab.Navigator>
    </NavigationContainer>
  );
};

const theme = {
  ...DefaultTheme,
  colors: {
    ...DefaultTheme.colors,
    secondaryContainer: 'transparent', // Use transparent to disable the little highlighting oval
  },
};

export default function Main() {
  return (
    <Provider theme={theme}>
      <App />
    </Provider>
  );
}

Fanchen Bao
  • 3,310
  • 1
  • 21
  • 34
  • You are my hero ! But I have a new problem, because i am using the shifting={true} with another color, when I click on the tab, I still see this ovale (for a short time) . Any idea ? I edited my post with the screen for the example – BenoHiT Jan 05 '23 at 11:23
  • Quick answer is to set `secondaryContainer: 'transparent'`, which actually resolves all of the issues with that little icon. I have also updated the answer and offered an example of rippling effect. – Fanchen Bao Jan 06 '23 at 01:36
0

Based on Fanchen Bao solution:

I couldn't trigger the useEffect cleanup (thus doesn't have access to the navigation and the current state). I found a possible alternative using the NavigatorContainer onStateChange prop and the state.index. The numbers depend on the order that you display the Tab.Screens.

Here's a docs reference about index (https://reactnavigation.org/docs/navigation-state/#partial-state-objects) :

This also applies to the index property: index should be the last route in a stack, and if a different value was specified, React Navigation fixes it.

It is not necessary the useNavigationContainerRef and useEffect for this case. I only copy the part I've added or changed:

I edit my answer since I've just tested it and it's also possible to use the NavigatorContainer theme prop and avoid the use of the Provider.

export default function App() {

// The numbers depends on the order that you display the Tab.Screens on the Tab.Navigator
const barColors = {
    // Tab.Screen home
    0: 'aqua',  
    // Tab.Screen settings
    1: 'gold',
    // Tab.Screen profile
    2: 'lawngreen',
  };

const [tab, setTab] = useState(0);

const stateChanger = (state) => {
  setTab(state.index)
}

const theme = {
      ...DefaultTheme,
      colors: {
        ...DefaultTheme.colors,
        secondaryContainer: 'transparent', // Use transparent to disable the little highlighting oval
      },
    };

return (
    <NavigationContainer  
        onStateChange={stateChanger}
        theme={theme}
    >


Jony
  • 51
  • 9