Why is the bottom tab navigator height smaller (squished) upon reload? - react-native

I am working with the createBottomTabNavigator() from React Navigation in my Expo application. I have 3 different tabs for different screen routing. Each tab consists of the screen name and an icon.
However, I am experiencing some inconsistent behavior after I reload the screen using expo. On the home screen load, the height of the bottom tab navigator appears to be "squished".
Squished Behavior: Notice in the picture below that the icons are to the left of the text and how thin the navigation bar is.
Normal Behavior: Now notice the "regular" behavior once I double click the home button or do some action to refresh the screen.
I can even navigate through the 3 navigation pages and it will stay in this "squished" state until I do something like double click home button (on iPhone this brings up your open applications - similar to the bottom right square Android button).
The code for the bottom tab navigation is below. There isn't anything fancy with it, just pretty standard stuff from the documentation.
import React from 'react';
import { StyleSheet } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { AntDesign, Ionicons } from '#expo/vector-icons';
const Tab = createBottomTabNavigator();
const HomeTab = createStackNavigator();
const UserProfileTab = createStackNavigator();
const NutritionTab = createStackNavigator();
function UserProfileScreen() {
return (
<UserProfileTab.Navigator
screenOptions={{
headerStyle: {
backgroundColor: Colors.topNavBar
},
headerTitleAlign: 'center'
}}>
<UserProfileTab.Screen name="Profile" component={UserProfile} />
</UserProfileTab.Navigator>
);
}
function NutritionScreen() {
return (
<NutritionTab.Navigator
screenOptions={{
headerStyle: {
backgroundColor: Colors.topNavBar
},
headerTitleAlign: 'center'
}}>
<NutritionTab.Screen name="Nutrition" component={Nutrition} />
</NutritionTab.Navigator>
);
}
function BottomTabs() {
return (
<>
<SafeAreaView style={{ flex: 0, backgroundColor: Colors.topNavBar }} />
<SafeAreaView style={{ flex: 1, backgroundColor: Colors.topNavBar }}>
<Tab.Navigator
initialRouteName="Home"
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home';
} else if (route.name === 'Profile') {
iconName = focused ? 'user' : 'user';
} else if (route.name === 'Nutrition') {
iconName = focused ? 'md-nutrition' : 'md-nutrition';
}
if (route.name === 'Nutrition') {
return <Ionicons name={iconName} size={size} color={color} />
}
return <AntDesign name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: Colors.bottomNavBarActive,
inactiveTintColor: Colors.bottomNavBarInactive,
tabStyle: styles.tabStyle,
labelStyle: styles.tabLabel,
}}>
<Tab.Screen
name="Nutrition"
component={NutritionScreen}
options={{ tabBarLabel: 'Nutrition' }}
/>
<Tab.Screen
name="Home"
component={MainStackNavigator}
/>
<Tab.Screen
name="Profile"
component={UserProfileScreen}
options={{ tabBarLabel: 'Profile' }}
/>
</Tab.Navigator>
</SafeAreaView>
</>
)
}
// Styling
const styles = StyleSheet.create({
tabStyle: {
backgroundColor: Colors.boxColor,
},
tabLabel: {
fontSize: 14,
},
});
export default function App() {
return (
<NavigationContainer>
<BottomTabs />
</NavigationContainer>
);
}
Has anyone ever faced an issue like this? Is it just some weird glitch with Expo?

Related

React-Native Header Title and Tab Navigator

I’ve a problem I cannot find an answer to, even though I’ve found similar problems with answers.
Basically, I pull a name (and other info) from a database. I then navigate to a screen (Screen A) in a tab navigator. I place the name into the header title of that screen (needed a stack navigator to do that I discovered from this site). I then have a second tab (Screen B) I can navigate to and want that same name placed in the header title there.
While on Screen B I also need to change the name and have that placed back into the header title of both Screen A and Screen B.
How do I do this? I have example code below that hopefully explains in more detail.
App.js
import React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { HomeScreen, ScreenA, ScreenB } from './ui/screens.js';
const AStack = createStackNavigator();
function ScreenAStack(headerProps) {
return (
<AStack.Navigator>
<AStack.Screen name="Screen A" component={ScreenA} />
</AStack.Navigator>
);
}
const BStack = createStackNavigator();
function ScreenBStack(headerProps) {
return (
<BStack.Navigator>
<BStack.Screen name="Screen B" component={ScreenB} />
</BStack.Navigator>
);
}
const BottomTab = createBottomTabNavigator();
function Tabs() {
return (
<BottomTab.Navigator
screenOptions={{ headerShown: false }}
>
<BottomTab.Screen name="Screen A Stack" options={{ title: "Screen A" }}>
{(props) => (
<ScreenAStack {...props} />
)}
</BottomTab.Screen>
<BottomTab.Screen name="Screen B Stack" options={{ title: "Screen B" }}>
{(props) => (
<ScreenBStack {...props} />
)}
</BottomTab.Screen>
</BottomTab.Navigator>
);
}
const Stack = createStackNavigator();
const App = () => {
return (
<NavigationContainer>{
<Stack.Navigator>
<>
<Stack.Screen name="Home Screen" options={() => ({ headerShown: true })} component={HomeScreen} />
<Stack.Screen name="Screen A Tabs" options={() => ({ headerShown: false })} component={Tabs} />
</>
</Stack.Navigator>
}</NavigationContainer>
);
}
export default App;
screens.js
import React, { useEffect } from 'react';
import { View, Text, TextInput, StyleSheet, Button, } from 'react-native';
export function HomeScreen({ navigation }) {
// Get name from server using api and send to Screen A.
navList = (item) => {
navigation.navigate("Screen A Tabs", {
screen: 'Screen A Stack',
params: {
screen: 'Screen A',
params: { item },
},
});
}
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen.</Text>
<Button title="Go to Tab Screen" onPress={() => navList({name: "Name here!"})} />
</View>
);
}
export function ScreenA({ route, navigation }) {
// Place name into header title.
useEffect(() => {
navigation.setOptions({
title: route.params.item.name,
});
}, [route]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Screen A</Text>
</View>
);
}
export function ScreenB({ navigation }) {
// Update header title with new name and update name on server using api.
const [newName, setNewName] = React.useState("");
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Screen B</Text>
<TextInput
value={newName}
onChangeText={newName => setNewName(newName)}
placeholder="Type new name here."
/>
<Button title="Change Name" onPress={() => console.log("Change name to " + newName)} />
</View>
);
}
I will give a short answer. your do not need to create a separate stacks for a single screen. here you can create a simple bottom tab navigator. just a sample.
<Tab.Navigator
initialRouteName="SearchScreen"
backBehavior="initialRoute"
screenOptions={{headerShown: false}}
>
<Tab.Screen
name="SearchScreen"
component={SearchScreen}
options={{
headerShown: false,
tabBarLabel: 'Search',
tabBarIcon: 'search',
}}
/>
<Tab.Screen
name="DialerScreen"
component={DialerScreen}
options={{
headerShown: false,
tabBarLabel: 'Dialer',
tabBarIcon: 'dialer',
}}
/>
</Tab.Navigator>
after this create a simple stack and add this bottom or top tab navigator like this
<Stack.Screen
name="Home"
component={TopTabNavigator}
options={{headerShown:true}}
/>
you can change title like this
onPress={() => {
if (item.is_analog) {
navigation.setOptions({title: 'Analog Speedo Meter'});
} else {
navigation.setOptions({title: 'Digital Speedo Meter'});
}
}}
cheers

How to change selected material bottom tab's splash color?

I just start react native.
How do I change the pink splash colour on the home tab?
The screenshot is from an android 12 device, but I tried it on an older android version and there isn't that splash pink colour but instead the standard android ripple effect.
app.tsx
import { StatusBar } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import Settings from './screens/settings';
import Home from './screens/home';
import Search from './screens/search';
const Tab = createMaterialBottomTabNavigator();
import {
StyleSheet,
SafeAreaView,
} from "react-native";
import React from 'react';
import { Icon } from 'react-native-elements';
export default function App() {
return (
<SafeAreaView style={styles.background}>
<NavigationContainer>
<Tab.Navigator
initialRouteName="Home"
shifting={true}
barStyle={{ backgroundColor: 'rgb(220, 220, 220)' }}
activeColor="black"
compact={false}
sceneAnimationEnabled={true}
inactiveColor='grey'
>
<Tab.Screen name="Settings" component={Settings} options={{
tabBarIcon: ({ focused, color }) => (
<Icon type='ionicon' name={focused ? 'settings' : "settings-outline"} color={color}></Icon>
),
}} />
<Tab.Screen name="Home" component={Home} options={{
tabBarIcon: ({ focused, color }) => (
<Icon type='ionicon' name={focused ? 'home' : "home-outline"} color={color}></Icon>
),
}} />
<Tab.Screen name="Search" component={Search} options={{
tabBarIcon: ({ focused, color }) => (
<Icon type='ionicon' name={focused ? 'search' : "search-outline"} color={color}></Icon>
),
}} />
</Tab.Navigator>
</NavigationContainer>
<StatusBar backgroundColor={'#fff'} barStyle={'dark-content'}></StatusBar>
</SafeAreaView >
);
}
const styles = StyleSheet.create({
background: {
backgroundColor: "#fff",
flex: 1.0
},
});
settings.tsx
function Settings() {
return (
<SafeAreaView style={styles.background}>
</SafeAreaView >
);
}
home.tsx
function Home() {
return (
<SafeAreaView style={styles.background}>
</SafeAreaView >
);
}
search.tsx
function Search() {
return (
<SafeAreaView style={styles.background}>
</SafeAreaView >
);
}
I erased some non relevant parts in the home, settings and search pages, for clearness.
I tried any settings that i could think of, but i didn't find any that would change that ugly pink color.

Hide Custom Tab Bar On A Specific Screen In React Navigation 6

I am writing a react native app with react-navigation 6 that has a custom tab navigation, inside of which I have multiple stacks for each tab.
Custom Bottom Tab with Stacks as Tabs:
<Tab.Navigator tabBar={props => <CustomTabBar {...props} />}>
<Tab.Screen
name={ROUTES.SPEAKER_STACK}
component={SpeakerNavigator}
options={{
title: 'Speakers',
tabBarLabel: 'Speakers',
tabBarIcon: { activeIcon: 'mic-sharp', inActiveIcon: 'mic-outline' },
}}
/>
</Tab.Navigator>
Speaker Navigator:
<Stack.Navigator initialRouteName={ROUTES.SPEAKERS}>
<Stack.Screen name={ROUTES.SPEAKERS} component={Speakers} />
<Stack.Screen name={ROUTES.SEND_MESSAGE} component={SendMessage} />
</Stack.Navigator>
CustomTab:
const CustomTabBar = ({ state, descriptors, navigation }) => {
return (
<View style={styles.tabBarContainer} shadow="3">
<View style={styles.slidingTabContainer}>
<Animated.View style={[styles.slidingTab, animatedTabStyles]} />
</View>
{state.routes.map((route, index) => {
return (
<Pressable
key={index}
style={{ flex: 1, alignItems: 'center' }}>
<TabIcon
tabIcon={tabBarIcon}
/>
</Pressable>
);
})}
</View>
);
}
Problem:
I want to hide the <CustomTab /> on the Send Message screen since it is a chat screen.
Already Tried:
<Tab.Screen
name={ROUTES.SPEAKER_STACK}
component={SpeakerNavigator}
options={({ route }) => {
if (getFocusedRouteNameFromRoute(route) === 'Send Message') {
return {
tabBarVisible: false,
tabBarStyle: { display: 'none' },
};
}
}}
/>
I assume they don't work since my TabBar is a custom component.
If I can somehow get getFocusedRouteNameFromRoute(route) === 'Send Message' inside the CustomTab component, I will be able to hide it directly by setting tabBarContainer (View wrapper of my custom tab bar) to display: 'none'
I have also tried the same technique from inside the screen. Same result.
react-navigation suggests to change the app structure by placing TabNavigator inside StackNavigator. But my app doesn't allow that structure.
import { View, Text, TouchableOpacity, SafeAreaView } from "react-native";
import type { BottomTabBarProps as ReactNavigationBottomTabBarProps } from "#react-navigation/bottom-tabs";
import { hp } from "#src/components/responsive";
import { CallOutlineIcon, ChatOutlineIcon } from "#src/components/icons";
type BottomTabBarProps = ReactNavigationBottomTabBarProps;
export default function TabBar({
state,
descriptors,
navigation,
}: BottomTabBarProps) {
const focusedOptions = descriptors[state.routes[state.index].key].options;
const { display } = focusedOptions?.tabBarStyle as {
display: "none" | "flex";
};
// ! HIDE BOTTOM TAB SPECIFICALLY FOR CHAT SCREEN
if (display === "none") {
return null;
}
// rest of the code
return (
<SafeAreaView>
</SafeAreaView>
);
}

how to remove this white ovale behind the focused in the Material Bottom Tabs Navigator

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?
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:
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.
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>
);
}

SafeArea color of bottom tab in dark mode cannot be changed

I have been stuck in this issue since yesterday and I cannot find a solution.
I have been trying to adjust the color of safeArea in iPhone X, it's working well on the top, and in the bottom as well for screens with no tab, however, in screens with tab navigator, the bottom safeArea is always white as shown in the screenshot. Does anyone know how to solve this issue?
Also, I want to ask if it would be better to use normal SafeAreaView component and remove the SafeAreaProvider and remove react-native-safe-area-context package, I just added it as a trial to solve this problem but I was first working with the react native normal SafeAreaView component;
In App component:
import { SafeAreaProvider } from "react-native-safe-area-context";
<SafeAreaProvider>
<NavigationContainer>
<CatNavigator />
</NavigationContainer>
</SafeAreaProvider>
In the CatNavigator component:
const CatNavigator = () => {
return (
<Drawer.Navigator
initialRouteName="Home" >
<Drawer.Screen
name="Home"
component={SettingsNavigator}
options={{ title: "Inicio" }}
/>
</Drawer.Navigator>
In the settings tab navigator:
const SettingsNavigator = () => {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
const iconType = Platform.OS === "ios" ? "ios" : "md";
if (route.name === "Home") {
iconName = iconType + "-home";
} else if (route.name === "Settings") {
iconName = iconType + "-settings";
}
const tabColor = focused ? Colors.buttonBackColor : Colors.titleColor;
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: Colors.activeTabColor,
inactiveTintColor: Colors.inactiveTabColor,
activeBackgroundColor: Colors.tabBackgroundColor,
inactiveBackgroundColor: Colors.tabBackgroundColor,
safeAreaInset: { bottom: "never", top: "never" },
}}
>
<Tab.Screen
name="Home"
component={HomeNavigator}
options={{ title: "Inicio" }}
/>
<Tab.Screen
name="Settings"
component={SettingStackNavigator}
options={{ title: "Ajustes" }}
/>
</Tab.Navigator>
In SettingsNavigator:
const SettingStackNavigator = (props) => {
return (
<SettingStack.Navigator screenOptions={defaultNavOptions}>
<SettingStack.Screen
name="Settings"
component={SettingScreen}
options={settingsOptions}
/>
</SettingStack.Navigator>
);
};
And finally in SettingScreen:
import { SafeAreaView } from "react-native-safe-area-context";
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: Colors.backgroundColor,
justifyContent: "center",
alignItems: "center",
}}
>
{colorScheme === "dark" && <StatusBar barStyle="light-content" />}
// Other components
</SafeAreaView>
If you want to change that little guy at the bottoms color you need add the style option to your Tab.Navigator, like so
tabBarOptions={{
style: {
backgroundColor: Colors.tabBackgroundColor,
},
}}