Skip to content

Commit 65e28bb

Browse files
committed
feat: add ability to hide tab labels in bottom navigation
1 parent cff1e56 commit 65e28bb

File tree

3 files changed

+1099
-48
lines changed

3 files changed

+1099
-48
lines changed

src/components/BottomNavigation.js

Lines changed: 64 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ type Props<T> = {
4141
* By default, this is `true` when you have more than 3 tabs.
4242
*/
4343
shifting?: boolean,
44+
/**
45+
* Whether to show labels in tabs. When `false`, only icons will be displayed.
46+
*/
47+
labeled?: boolean,
4448
/**
4549
* State for the bottom navigation. The state should contain the following properties:
4650
*
@@ -289,6 +293,10 @@ class BottomNavigation<T: *> extends React.Component<Props<T>, State> {
289293
);
290294
}
291295

296+
static defaultProps = {
297+
labeled: true,
298+
};
299+
292300
static getDerivedStateFromProps(nextProps, prevState) {
293301
const { index, routes } = nextProps.navigationState;
294302

@@ -436,6 +444,7 @@ class BottomNavigation<T: *> extends React.Component<Props<T>, State> {
436444
activeTintColor,
437445
inactiveTintColor,
438446
barStyle,
447+
labeled,
439448
style,
440449
theme,
441450
} = this.props;
@@ -574,20 +583,23 @@ class BottomNavigation<T: *> extends React.Component<Props<T>, State> {
574583
const focused = this.state.tabs[index];
575584

576585
// Scale up in the label
577-
const scale = shifting
578-
? focused.interpolate({
579-
inputRange: [0, 1],
580-
outputRange: [0.5, 1],
581-
})
582-
: 1;
586+
const scale =
587+
labeled && shifting
588+
? focused.interpolate({
589+
inputRange: [0, 1],
590+
outputRange: [0.5, 1],
591+
})
592+
: 1;
583593

584594
// Move down the icon to account for no-label in shifting and smaller label in non-shifting.
585-
const translateY = shifting
586-
? focused.interpolate({
587-
inputRange: [0, 1],
588-
outputRange: [10, 0],
589-
})
590-
: 0;
595+
const translateY = labeled
596+
? shifting
597+
? focused.interpolate({
598+
inputRange: [0, 1],
599+
outputRange: [10, 0],
600+
})
601+
: 0
602+
: 10;
591603

592604
// We render the active icon and label on top of inactive ones and cross-fade them on change.
593605
// This trick gives the illusion that we are animating between active and inactive colors.
@@ -651,67 +663,71 @@ class BottomNavigation<T: *> extends React.Component<Props<T>, State> {
651663
)}
652664
</Animated.View>
653665
</Animated.View>
654-
<Animated.View
655-
style={[
656-
styles.labelContainer,
657-
{
658-
transform: [{ scale }],
659-
},
660-
]}
661-
>
666+
{labeled ? (
662667
<Animated.View
663668
style={[
664-
styles.labelWrapper,
665-
{ opacity: activeOpacity },
669+
styles.labelContainer,
670+
{
671+
transform: [{ scale }],
672+
},
666673
]}
667674
>
668-
{renderLabel ? (
669-
renderLabel({
670-
route,
671-
focused: true,
672-
tintColor: activeColor,
673-
})
674-
) : (
675-
<AnimatedText
676-
style={[
677-
styles.label,
678-
{
679-
color: activeColor,
680-
},
681-
]}
682-
>
683-
{getLabelText({ route })}
684-
</AnimatedText>
685-
)}
686-
</Animated.View>
687-
{shifting ? null : (
688675
<Animated.View
689676
style={[
690677
styles.labelWrapper,
691-
{ opacity: inactiveOpacity },
678+
{ opacity: activeOpacity },
692679
]}
693680
>
694681
{renderLabel ? (
695682
renderLabel({
696683
route,
697-
focused: false,
698-
tintColor: inactiveColor,
684+
focused: true,
685+
tintColor: activeColor,
699686
})
700687
) : (
701688
<AnimatedText
702689
style={[
703690
styles.label,
704691
{
705-
color: inactiveColor,
692+
color: activeColor,
706693
},
707694
]}
708695
>
709696
{getLabelText({ route })}
710697
</AnimatedText>
711698
)}
712699
</Animated.View>
713-
)}
714-
</Animated.View>
700+
{shifting ? null : (
701+
<Animated.View
702+
style={[
703+
styles.labelWrapper,
704+
{ opacity: inactiveOpacity },
705+
]}
706+
>
707+
{renderLabel ? (
708+
renderLabel({
709+
route,
710+
focused: false,
711+
tintColor: inactiveColor,
712+
})
713+
) : (
714+
<AnimatedText
715+
style={[
716+
styles.label,
717+
{
718+
color: inactiveColor,
719+
},
720+
]}
721+
>
722+
{getLabelText({ route })}
723+
</AnimatedText>
724+
)}
725+
</Animated.View>
726+
)}
727+
</Animated.View>
728+
) : (
729+
<View style={styles.labelContainer} />
730+
)}
715731
</View>
716732
</Touchable>
717733
);

src/components/__tests__/BottomNavigation.test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,35 @@ it('renders custom icon and label with custom colors in non-shifting bottom navi
128128

129129
expect(tree).toMatchSnapshot();
130130
});
131+
132+
it('hides labels in shifting bottom navigation', () => {
133+
const tree = renderer
134+
.create(
135+
<BottomNavigation
136+
shifting
137+
labeled={false}
138+
navigationState={createState(0, 3)}
139+
onIndexChange={jest.fn()}
140+
renderScene={({ route }) => route.title}
141+
/>
142+
)
143+
.toJSON();
144+
145+
expect(tree).toMatchSnapshot();
146+
});
147+
148+
it('hides labels in non-shifting bottom navigation', () => {
149+
const tree = renderer
150+
.create(
151+
<BottomNavigation
152+
shifting={false}
153+
labeled={false}
154+
navigationState={createState(0, 3)}
155+
onIndexChange={jest.fn()}
156+
renderScene={({ route }) => route.title}
157+
/>
158+
)
159+
.toJSON();
160+
161+
expect(tree).toMatchSnapshot();
162+
});

0 commit comments

Comments
 (0)