Created
June 8, 2019 16:30
-
-
Save VojtaSim/6203b217f3819c96ab0de2f1b37427a9 to your computer and use it in GitHub Desktop.
react-navigation: Shazam-like TabBar with dots
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { View, SafeAreaView, Animated } from 'react-native'; | |
import { NavigationState } from 'react-navigation'; | |
import { SceneRendererProps } from 'react-native-tab-view'; | |
import Styles, { DOT_SIZE, DOT_MARGIN, BAR_WIDTH } from './styles'; | |
type ScreenDotsProps = SceneRendererProps & { | |
state: NavigationState | |
}; | |
type ScreenDotsState = { | |
barWidth: Animated.AnimatedInterpolation, | |
barPosition: Animated.AnimatedSubtraction, | |
} | |
export default class ScreenDots extends Component<ScreenDotsProps, ScreenDotsState> { | |
constructor(props) { | |
super(props); | |
const barWidth = this.getBarWithInterpolation(); | |
this.state = { | |
barWidth, | |
barPosition: this.getBarPositionInterpolation(barWidth) | |
}; | |
} | |
render() { | |
const { routes } = this.props.navigation.state; | |
const { barWidth, barPosition } = this.state; | |
return ( | |
<SafeAreaView style={Styles.container}> | |
<View style = {Styles.dotsContainer}> | |
{routes.map((route, index) => ( | |
<View key={route.key} style={[ | |
Styles.dot, | |
index === 0 ? null : { marginLeft: DOT_MARGIN } | |
]} /> | |
))} | |
<Animated.View style = {[ | |
Styles.bar, | |
{ | |
width: barWidth, | |
left: barPosition | |
} | |
]}/> | |
</View> | |
</SafeAreaView> | |
) | |
} | |
getBarWithInterpolation() { | |
const { position, navigation } = this.props; | |
const { routes } = navigation.state; | |
const indexPhase = [0.3, 0.7, 1]; | |
const widthPhase = [BAR_WIDTH, BAR_WIDTH, DOT_SIZE]; | |
const routeIndexes = routes.reduce( | |
(indexes, _, index) => indexes.concat(indexPhase.map(i => index + i)), | |
[0] | |
); | |
return position.interpolate({ | |
inputRange: routeIndexes, | |
outputRange: routes.reduce(phases => phases.concat(widthPhase), [DOT_SIZE]), | |
extrapolate: 'clamp' | |
}); | |
} | |
getBarPositionInterpolation(widthInterpolation) { | |
const { position, navigation } = this.props; | |
const { routes } = navigation.state; | |
const routeIndexes = routes.map((_, index) => index); | |
return Animated.subtract( | |
position.interpolate({ | |
inputRange: routeIndexes, | |
outputRange: routes.map((_, index) => (DOT_SIZE + DOT_MARGIN) * index), | |
extrapolate: 'clamp' | |
}), | |
Animated.divide(widthInterpolation, 2) | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { StyleSheet } from 'react-native'; | |
export const DOT_SIZE = 10; | |
export const DOT_MARGIN = 14; | |
export const BAR_WIDTH = DOT_SIZE + DOT_MARGIN; | |
export default StyleSheet.create({ | |
container: { | |
position: 'absolute', | |
left: 0, | |
top: 0, | |
right: 0, | |
flexDirection: 'row', | |
flexWrap: 'nowrap', | |
justifyContent: 'center', | |
zIndex: 100, | |
}, | |
dotsContainer: { | |
position: 'relative', | |
flexDirection: 'row', | |
flexWrap: 'nowrap', | |
justifyContent: 'center' | |
}, | |
dot: { | |
backgroundColor: '#000', | |
borderRadius: DOT_SIZE, | |
height: DOT_SIZE, | |
width: DOT_SIZE, | |
opacity: 0.5 | |
}, | |
bar: { | |
backgroundColor: '#000', | |
borderRadius: DOT_SIZE, | |
height: DOT_SIZE, | |
opacity: 1, | |
position: 'absolute', | |
bottom: 0, | |
marginLeft: DOT_SIZE / 2 | |
}, | |
indicator: { | |
position: 'absolute', | |
bottom: 0, | |
left: 0, | |
backgroundColor: 'red', | |
height: 3, | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello, how do I use this? I want to implement it with react-native-tab-view. Thanks!