react-native-tab-view
react-native-tab-view copied to clipboard
`renderLabel` and `renderIcon` wrap or cut off text/icon if unfocused text/icon is smaller than focused text
Current behaviour
If the Text component returned by renderLabel
when focused
is false
is smaller (in width) than the Text returned when focused
is true
, then the Text component for focused tab gets wrapped.
Similar issue exists with renderIcon
. If the Icon returned by renderIcon
when focused
is false
is smaller (in width and height) than the Icon returned when focused
is true
, then the Icon for focused tab gets cut off.
Neither of the issues happen when the focused one is smaller than the unfocused one. Infact, that causes another issue where the box designated for focused version is larger than it needs and it gets offcenter.
It seems that in both the cases, the text is drawn within a box of width of the unfocused component.
Expected behaviour
The icon and text should get enough space to be drawn.
Code sample
import * as React from 'react';
import { View, StyleSheet, Dimensions, Text } from 'react-native';
import { TabView, TabBar, SceneMap } from 'react-native-tab-view';
const FirstRoute = () => (
<View style={[styles.scene, { backgroundColor: '#ff4081' }]} />
);
const SecondRoute = () => (
<View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);
function renderLabel({ route, focused, color }) {
return <Text style={{ color }}>{focused ? route.title : ' '}</Text>;
}
const initialLayout = { width: Dimensions.get('window').width };
export default function App() {
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
]);
const renderScene = SceneMap({
first: FirstRoute,
second: SecondRoute,
});
return (
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
renderTabBar={props => <TabBar {...props} renderLabel={renderLabel} />}
/>
);
}
const styles = StyleSheet.create({
scene: {
flex: 1,
},
});
Above code: https://snack.expo.io/HySYUg6UL
Changing renderLabel
to the following code will display the offcenter issue
function renderLabel({ route, focused, color }) {
return <Text style={{ color }}>{focused ? 'x' : 'a bit long text'}</Text>;
}
Code with above modification: https://snack.expo.io/B1qdDg6UU
Screenshots (if applicable)
Wrapping issue
Offcenter issue
What have you tried
My current workaround for hiding labels on inactive tabs (I only want to show icons) is to set text color as color of tab bar. this isn't exactly perfect since the text becomes partially visible during a tap and isn't useful in all cases (e.g. if you want to show an abbrevation in non focused cases).
Your Environment
software | version |
---|---|
android | 9.0 |
react-native | 3.2.1 |
react-native-tab-view | 2.13.0 |
react-native-gesture-handler | 1.6.0 |
react-native-reanimated | 1.7.0 |
node | 13.8.0 |
yarn | 1.22.0 |
me too
I have a very similar issue. My render label function bolds focused tab. This causes an issue on android where the last character gets wrapped to the the next line when the tab is focused.
@shockoe-hatch that is definitely the same issue! Making the text bold will increase the width of the text so since width of focused text will be larger than unfocused text, it will wrap.
I'm still waiting for this issue to be fixed.
For anyone looking for a quick hack to work around this issue, I have setup my renderLabel
to render two Text
components, one is the "largest" size and is essentially hidden by being the same color as the background color and the "smallest" is then positioned absolute over it.
renderLabel={({ route, focused }) => (
<View>
<Text style={[...styles.tabBarLabelActive, { color: 'white' }]}>
{route.title?.toUpperCase()}
</Text>
<Text
style={[
...(focused
? styles.tabBarLabelActive
: styles.tabBarLabel),
{ position: 'absolute' },
]}
>
{route.title?.toUpperCase()}
</Text>
</View>
)}
@MPiccinato this worked for me! Thanks!
So I found a better solution, leaving the bold text rendered on the screen from the start, along with the main text, however transparent and with a small size. The problem I see is that the lib does not render again when changing the font size, which causes a mismatch with the layout, some memoization or pure components.
My solution:
renderLabel={({route, focused}) => {
return (
<View>
<Text style={{fontWeight: focused ? 'bold' : 'normal'}}>
{route.title}
</Text>
<View style={{height: 1}}>
<Text
style={{
fontWeight: 'bold',
color: 'transparent',
}}>
{route.title}
</Text>
</View>
</View>
);
}}
Hello, is there any update to the issue? it's still present in v3.1.1
borderWidth: 1, borderColor: "transparent", Try to add this to text style. It's working for me.
To fix this issue, custom the width of the possible text :
<TabView
navigationState={{index, routes}}
renderTabBar={props => (
<TabBar
{...props}
indicatorStyle={{backgroundColor: colors.primary,height:1,bottom:-1}}
style={{
backgroundColor: 'white',
elevation: 0,
borderBottomWidth: 1,
borderColor: colors.gray[200],
paddingVertical:spacing.tiny,
}}
inactiveColor={colors.gray[800]}
activeColor={colors.primary}
renderLabel={({route, focused, color}) => (
<Text
color={color}
// make the width for the text fixed
**style={{width:100,textAlign:"center"}}**
variant={focused ? 'largeSemiBold' : 'mediumRegular'}
>
{route.title}
</Text>
)}
/>)}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={{width: layout.width
}}
/>