Skip to content

Instantly share code, notes, and snippets.

@dilipsuthar97
Created March 5, 2021 15:52
Show Gist options
  • Save dilipsuthar97/523da9ad1e38e6feab576cd5a688126e to your computer and use it in GitHub Desktop.
Save dilipsuthar97/523da9ad1e38e6feab576cd5a688126e to your computer and use it in GitHub Desktop.
import React from 'react';
import {
StyleSheet,
Text,
View,
StatusBar,
Dimensions,
Image,
Animated,
findNodeHandle,
TouchableOpacity,
} from 'react-native';
const {width, height} = Dimensions.get('screen');
const images = {
man:
'https://images.pexels.com/photos/3147528/pexels-photo-3147528.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
women:
'https://images.pexels.com/photos/2552130/pexels-photo-2552130.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
kids:
'https://images.pexels.com/photos/5080167/pexels-photo-5080167.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
skullcandy:
'https://images.pexels.com/photos/5602879/pexels-photo-5602879.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
help:
'https://images.pexels.com/photos/2552130/pexels-photo-2552130.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
};
const data = Object.keys(images).map((i) => ({
key: i,
title: i,
image: images[i],
ref: React.createRef(),
}));
const Tab = React.forwardRef(({item, onItemPress}, ref) => {
return (
<TouchableOpacity delayPressIn={0} onPress={onItemPress}>
<View ref={ref}>
<Text
style={{
color: 'white',
fontSize: 84 / data.length,
fontWeight: '800',
textTransform: 'uppercase',
}}>
{item.title}
</Text>
</View>
</TouchableOpacity>
);
});
const Tabs = ({data, scrollX, onItemPress}) => {
const containerRef = React.useRef();
const [measures, setMeasures] = React.useState([]);
React.useEffect(() => {
let m = [];
data.forEach((item) => {
item.ref.current.measureLayout(
containerRef.current,
(x, y, width, height) => {
m.push({
x,
y,
width,
height,
});
if (m.length === data.length) {
setMeasures(m);
}
},
);
});
}, []);
console.log(measures.length);
return (
<View style={{position: 'absolute', top: 100, width}}>
<View
ref={containerRef}
style={{flexDirection: 'row', flex: 1, justifyContent: 'space-evenly'}}>
{data.map((item, index) => {
return (
<Tab
key={item.key}
item={item}
ref={item.ref}
onItemPress={() => onItemPress(index)}
/>
);
})}
</View>
{measures.length > 0 && (
<Indicator measures={measures} scrollX={scrollX} />
)}
</View>
);
};
const Indicator = ({measures, scrollX}) => {
const inputRange = data.map((_, i) => i * width);
const indicatorWidth = scrollX.interpolate({
inputRange,
outputRange: measures.map((m) => m.width),
});
const translateX = scrollX.interpolate({
inputRange,
outputRange: measures.map((m) => m.x),
});
return (
<Animated.View
style={{
position: 'absolute',
width: indicatorWidth,
height: 2,
backgroundColor: 'white',
bottom: -10,
transform: [{translateX}],
}}
/>
);
};
export default function App() {
const scrollX = React.useRef(new Animated.Value(0)).current;
const ref = React.useRef();
const onItemPress = React.useCallback((itemIndex) => {
ref.current.scrollToOffset({
offset: itemIndex * width,
});
});
return (
<View style={styles.container}>
<StatusBar hidden />
<Animated.FlatList
ref={ref}
data={data}
keyExtractor={(item) => item.key}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
bounces={false}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: scrollX}}}],
{useNativeDriver: false},
)}
renderItem={({item}) => {
return (
<View style={{width, height}}>
<Image
source={{uri: item.image}}
style={{flex: 1, resizeMode: 'cover'}}
/>
<View
style={[
StyleSheet.absoluteFillObject,
{backgroundColor: 'rgba(0,0,0,0.3)'},
]}
/>
</View>
);
}}
/>
<Tabs scrollX={scrollX} data={data} onItemPress={onItemPress} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment