Last active
September 8, 2021 16:21
-
-
Save anastely/e6dde4379ec6ec62698d1407f06487fa to your computer and use it in GitHub Desktop.
This file contains 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, { useEffect, useRef, useState } from "react"; | |
import { | |
Dimensions, | |
FlatList, | |
I18nManager, | |
StyleSheet, | |
Text, | |
TouchableOpacity, | |
View, | |
} from "react-native"; | |
const { width } = Dimensions.get("window"); | |
const headers = [ | |
"header1", | |
"header header 2", | |
"header3", | |
"header header4", | |
"header5", | |
"header header6", | |
"header7", | |
"header header8", | |
"header9", | |
"header10", | |
]; | |
const content = [...Array(10).keys()].fill(0); | |
const TAB_WIDTH = 150; | |
const HeaderTabView = () => { | |
const [activeIndex, setActiveIndex] = useState(0); | |
const headerRef = useRef(); | |
const contentRef = useRef(); | |
const scrollToActiveIndex = (index) => { | |
// current active page (index) | |
setActiveIndex(index); | |
// scroll the content when press tab | |
contentRef.current.scrollToOffset({ | |
offset: index * width, | |
animated: true, | |
}); | |
// if the tab width is greater than half(middle) of the screen, scroll to the middle of the screen otherwise set offset 0 | |
if (index * TAB_WIDTH - TAB_WIDTH / 2 > width / 2) { | |
headerRef.current.scrollToOffset({ | |
offset: index * TAB_WIDTH - width / 2 + TAB_WIDTH / 2, | |
animated: true, | |
}); | |
} else { | |
headerRef.current.scrollToOffset({ | |
offset: 0, | |
animated: true, | |
}); | |
} | |
}; | |
return ( | |
<View style={styles.container}> | |
<FlatList | |
data={headers} | |
style={{ | |
flexGrow: 0, | |
flexDirection: I18nManager.isRTL ? "row-reverse" : "row", | |
}} | |
ref={headerRef} | |
contentContainerStyle={{ | |
flexGrow: 1, | |
}} | |
keyExtractor={(item, index) => index.toString()} | |
horizontal | |
showsHorizontalScrollIndicator={false} | |
renderItem={({ item, index }) => ( | |
<View style={{ width: TAB_WIDTH }}> | |
<TouchableOpacity | |
onPress={() => scrollToActiveIndex(index)} | |
key={item} | |
style={[ | |
styles.headerItem, | |
{ | |
backgroundColor: activeIndex == index ? "#b6d7fc" : "#82bcff", | |
}, | |
]}> | |
<Text>{item}</Text> | |
</TouchableOpacity> | |
{activeIndex == index && <View style={styles.headerBar} />} | |
</View> | |
)} | |
/> | |
<FlatList | |
data={content} | |
ref={contentRef} | |
keyExtractor={(item, index) => index.toString()} | |
horizontal | |
pagingEnabled | |
onMomentumScrollEnd={(ev) => { | |
scrollToActiveIndex( | |
Math.floor(ev.nativeEvent.contentOffset.x / width), | |
); | |
}} | |
decelerationRate="fast" | |
renderItem={({ item, index }) => ( | |
<View key={item} style={styles.mainItem}> | |
<Text>Animation happens once scrolling ended</Text> | |
<Text>card {index + 1}</Text> | |
</View> | |
)} | |
/> | |
</View> | |
); | |
}; | |
export default HeaderTabView; | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
}, | |
headerScroll: { | |
flexGrow: 0, | |
}, | |
headerItem: { | |
alignItems: "center", | |
justifyContent: "center", | |
padding: 20, | |
}, | |
mainItem: { | |
width: width, | |
borderWidth: 5, | |
borderColor: "#fff", | |
backgroundColor: "#ccc", | |
alignItems: "center", | |
justifyContent: "space-evenly", | |
}, | |
headerBar: { | |
height: 2, | |
width: "90%", | |
alignSelf: "center", | |
backgroundColor: "#000", | |
position: "absolute", | |
bottom: 0, | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment