Skip to content

Instantly share code, notes, and snippets.

@dilipsuthar97
Last active November 22, 2021 09:42
Show Gist options
  • Save dilipsuthar97/ac02fb234b4465734443bfb441b736c3 to your computer and use it in GitHub Desktop.
Save dilipsuthar97/ac02fb234b4465734443bfb441b736c3 to your computer and use it in GitHub Desktop.
// --------------- LIBRARIES ---------------
import * as React from 'react';
import { View, TouchableOpacity, StyleSheet, Platform } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const {
event,
Value,
interpolate,
interpolateColors,
useCode,
call,
} = Animated;
// --------------- ASSETS ---------------
import { Fonts, Colors, Matrics, MainStyles } from '../CommonConfig';
export default React.forwardRef(
(
{
scens,
routes,
initialIndex,
scrollEnabled,
onIndexChange,
animatedScrollX,
},
ref,
) => {
React.useImperativeHandle(ref, () => ({
getActiveIndex: () => activeIndex,
}));
const scrollX = animatedScrollX
? animatedScrollX
: React.useRef(new Value(0)).current;
const refSlider = React.useRef();
const [activeIndex, setActiveIndex] = React.useState(0);
const onPressTab = React.useCallback((itemIndex) => {
refSlider.current.getNode().scrollToOffset({
offset: itemIndex * Matrics.screenWidth,
});
}, []);
const _getItemLayout = React.useCallback((data, index) => {
return {
length: Matrics.screenWidth,
offset: Matrics.screenWidth * index,
index,
};
}, []);
const _viewConfigRef = React.useRef({
viewAreaCoveragePercentThreshold: 50,
});
const _onViewRef = React.useRef(({ viewableItems }) => {
if (viewableItems && viewableItems.length > 0) {
onIndexChange && onIndexChange(viewableItems[0].index);
setActiveIndex(viewableItems[0].index);
}
});
/**
* Listen to animated value change
*/
/*useCode(() => {
return call([scrollX], (scrollX) => {
console.log(scrollX);
});
}, [scrollX]);*/
return (
<View style={styles.container}>
<Tabs
scrollX={scrollX}
data={routes}
onTabPress={onPressTab}
activeIndex={activeIndex}
/>
<AnimatedFlatList
ref={refSlider}
horizontal
pagingEnabled
scrollEnabled={scrollEnabled ?? true}
bounces={false}
overScrollMode='never'
showsHorizontalScrollIndicator={false}
initialScrollIndex={initialIndex ?? 0}
keyExtractor={(item, index) => `tab_screen_${index}`}
data={scens}
onScroll={event([
{
nativeEvent: {
contentOffset: { x: scrollX },
},
},
])}
renderItem={({ item }) => {
return (
<View style={{ width: Matrics.screenWidth }}>
{item}
</View>
);
}}
getItemLayout={_getItemLayout}
viewabilityConfig={_viewConfigRef.current}
onViewableItemsChanged={_onViewRef.current}
/>
</View>
);
},
);
const Tabs = ({ data, scrollX, onTabPress, activeIndex }) => {
const inputRange = data.map((_, i) => i * Matrics.screenWidth);
return (
<View
style={{
backgroundColor: Colors.WHITE,
zIndex: 1,
...MainStyles.shadow([0, 1], 0.08, 4, 2),
}}>
<View style={styles.tabBar}>
{data.map((item, index) => {
return (
<Tab
key={`tab_${index}`}
inputRange={inputRange}
item={item}
onTabPress={() => onTabPress(index)}
scrollX={scrollX}
index={index}
activeIndex={activeIndex}
/>
);
})}
</View>
<Indicator inputRange={inputRange} scrollX={scrollX} />
</View>
);
};
const Tab = ({ item, onTabPress, scrollX, inputRange, index, activeIndex }) => {
// const outputRange = inputRange.map((_, i) =>
// i == index ? Colors.PRIMARY : Colors.TOP_TAB_INACTIVE,
// );
// const color = interpolateColors(scrollX, {
// inputRange,
// outputColorRange: outputRange,
// });
const color =
index == activeIndex ? Colors.PRIMARY : Colors.TOP_TAB_INACTIVE;
return (
<TouchableOpacity
delayPressIn={0}
activeOpacity={0.5}
onPress={onTabPress}>
<View
style={[
styles.tab,
{ width: Matrics.screenWidth / inputRange.length },
]}>
{item?.icon && (
<Animated.Image
source={item.icon}
style={[
styles.icon,
{
tintColor: color,
},
]}
resizeMode={'contain'}
/>
)}
<Animated.Text
style={[
styles.topTabLableText,
{
color,
},
]}>
{item.title}
</Animated.Text>
</View>
</TouchableOpacity>
);
};
const Indicator = ({ scrollX, inputRange }) => {
const tabWidth = Matrics.screenWidth / inputRange.length;
const translateX = interpolate(scrollX, {
inputRange,
outputRange: inputRange.map((_, i) => i * tabWidth),
});
return (
<Animated.View
style={[
styles.indicator,
{
width: tabWidth,
transform: [{ translateX }],
},
]}
/>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
zIndex: -1,
},
indicator: {
backgroundColor: Colors.PRIMARY,
height: Matrics.vs(2),
},
tabBar: {
flexDirection: 'row',
height: Platform.OS == 'ios' ? Matrics.vs(35) : Matrics.vs(45),
},
tab: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
icon: {
width: Matrics.mvs(15),
height: Matrics.mvs(15),
},
topTabLableText: {
fontSize: Matrics.mvs(15),
fontFamily: Fonts.Medium,
marginLeft: Matrics.s(10),
},
});
@dilipsuthar97
Copy link
Author

Modified code

@dilipsuthar97
Copy link
Author

Replaced Animated with react-native-reanimated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment