Skip to content

Instantly share code, notes, and snippets.

@nelsonprsousa
Created February 9, 2021 10:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nelsonprsousa/a2ddf6a95a3f5dc0cfddcc563c427815 to your computer and use it in GitHub Desktop.
Save nelsonprsousa/a2ddf6a95a3f5dc0cfddcc563c427815 to your computer and use it in GitHub Desktop.
import React from 'react';
import {View, Dimensions} from 'react-native';
import Animated, {
useAnimatedScrollHandler,
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated';
const BORDER_RADIUS = 10;
const SCREEN_WIDTH = Dimensions.get('screen').width;
const palette = [
'#FFB3B3',
'#FFDCB3',
'#FFF8B3',
'#E2FFB3',
'#B3FFDB',
'#B3DBFF',
'#B3BBFF',
'#DEB3FF',
];
const CARD_WIDTH = 260;
const IMAGE_HEIGHT = Math.floor((CARD_WIDTH / 16) * 9);
const CARD_HEIGHT = IMAGE_HEIGHT + 100;
const MARGIN = 16;
const SCALE = 0.85;
const Card = ({index, lastOne, scroll}) => {
const animated = useAnimatedStyle(() => {
let value = 1;
const current = Math.round(scroll.value);
if (index === current - 1 || index === current + 1) {
const offset = 2 * Math.abs(scroll.value - current);
value = SCALE + offset * (1 - SCALE);
}
return {
transform: [{scale: value}],
};
});
return (
<View
style={{
width: CARD_WIDTH,
height: CARD_HEIGHT,
marginRight: lastOne ? 0 : MARGIN,
}}>
<Animated.View
style={[
{
width: CARD_WIDTH,
height: CARD_HEIGHT,
borderRadius: BORDER_RADIUS,
backgroundColor: '#fff',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.1,
shadowRadius: 4,
},
animated,
]}>
<View
style={{
width: CARD_WIDTH,
height: IMAGE_HEIGHT,
backgroundColor: palette[index],
borderTopLeftRadius: BORDER_RADIUS,
borderTopRightRadius: BORDER_RADIUS,
}}
/>
<View style={{padding: 16}}></View>
</Animated.View>
</View>
);
};
const Cards = ({items}) => {
const scroll = useSharedValue(0);
const handleScroll = useAnimatedScrollHandler(({contentOffset: {x}}) => {
const current = x / (CARD_WIDTH + MARGIN);
scroll.value = current;
});
return (
<Animated.ScrollView
snapToInterval={CARD_WIDTH + MARGIN}
contentOffset={{
y: 0,
x: (CARD_WIDTH + MARGIN) * Math.floor(items.length / 2),
}}
decelerationRate="fast"
horizontal
showsHorizontalScrollIndicator={false}
onScroll={handleScroll}
scrollEventThrottle={16}
style={{
top: 0,
left: 0,
position: 'absolute',
paddingVertical: 20 + 16,
}}
contentContainerStyle={{
paddingHorizontal: (SCREEN_WIDTH - CARD_WIDTH) / 2,
}}>
{items.map((item, index) => (
<Card
index={index}
scroll={scroll}
lastOne={index === items.length - 1}
/>
))}
</Animated.ScrollView>
);
};
export default Cards;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment