Skip to content

Instantly share code, notes, and snippets.

@dheysonalves
Created August 11, 2021 04:42
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 dheysonalves/120f3022f721ffd9f43cc71823164187 to your computer and use it in GitHub Desktop.
Save dheysonalves/120f3022f721ffd9f43cc71823164187 to your computer and use it in GitHub Desktop.
Animated Cards Testing
/* eslint-disable guard-for-in */
/* eslint-disable no-restricted-syntax */
import React, { useState, useCallback } from 'react';
import { useWindowDimensions } from 'react-native';
import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, {
cancelAnimation,
runOnJS,
scrollTo,
useAnimatedGestureHandler,
useAnimatedReaction,
useAnimatedRef,
useAnimatedScrollHandler,
useAnimatedStyle,
useSharedValue,
withSpring,
withTiming,
} from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useTheme } from '#common/context';
import { DashboardCard } from '#core/components';
import { DashboardCardsProps } from './dashboardcards.type';
const DASHBOARD_CARD_HEIGHT = 90.0;
const SCROLL_HEIGHT_THRESHOLD = DASHBOARD_CARD_HEIGHT;
const elementsArray = [
{
id: 'requested',
clientCardType: 'requested',
cardState: 'approved',
gradientColors: ['#fff', '#fff'],
headerTitle: 'Acompanhe seu cartão',
headerTitleColor: '#000',
position: 0,
},
{
id: 'credit',
clientCardType: 'credit',
cardState: 'analysis',
headerTitle: 'Cartão de Crédito',
headerTitleColor: '#fff',
gradientColors: ['#EC008C', '#62003A'],
position: 100,
},
{
id: 'digital',
clientCardType: 'requested',
cardState: 'approved',
gradientColors: ['#0D223A', '#1D57A5'],
headerTitle: 'Conta Digital',
headerTitleColor: '#fff',
position: 190,
},
];
function clamp(value: any, lowerBound: any, upperBound: any) {
'worklet';
return Math.max(lowerBound, Math.min(value, upperBound));
}
function objectMove(object: any, from: any, to: any) {
'worklet';
const newObject = { ...object };
for (const id in object) {
if (object[id] === from) {
newObject[id] = to;
}
if (object[id] === to) {
newObject[id] = from;
}
}
return newObject;
}
function listToObject(list: any) {
const values = Object.values(list);
const object = {};
for (let i = 0; i < values.length; i++) {
object[values[i].id] = i;
}
return object;
}
function MovableCard({
clientCardType,
cardState,
positions,
headerTitle,
id,
headerTitleColor,
gradientColors,
scrollY,
cardsCount,
}: {
clientCardType: string;
cardState: string;
headerTitle: string;
id: number | string;
headerTitleColor: string;
gradientColors: string[];
positions: any;
scrollY: any;
cardsCount: number;
}) {
const [moving, setMoving] = useState(false);
const top = useSharedValue(positions.value[id] * DASHBOARD_CARD_HEIGHT);
const dimensions = useWindowDimensions();
const insets = useSafeAreaInsets();
useAnimatedReaction(
() => positions.value[id],
(currentPosition, previousPosition) => {
if (currentPosition !== previousPosition) {
if (!moving) {
top.value = withSpring(currentPosition * DASHBOARD_CARD_HEIGHT);
}
}
},
[moving],
);
const gestureHandler = useAnimatedGestureHandler({
onStart() {
runOnJS(setMoving)(true);
},
onActive(event) {
const positionY = event.absoluteY + scrollY.value;
if (positionY <= scrollY.value + SCROLL_HEIGHT_THRESHOLD) {
// Scroll up
scrollY.value = withTiming(0, { duration: 1500 });
} else if (
positionY >=
scrollY.value + dimensions.height - SCROLL_HEIGHT_THRESHOLD
) {
// Scroll down
const contentHeight = cardsCount * DASHBOARD_CARD_HEIGHT;
const containerHeight = dimensions.height - insets.top - insets.bottom;
const maxScroll = contentHeight - containerHeight;
scrollY.value = withTiming(maxScroll, { duration: 1500 });
} else {
cancelAnimation(scrollY);
}
top.value = withTiming(positionY - DASHBOARD_CARD_HEIGHT, {
duration: 16,
});
// CRASHES HERE WHEM USING IT
const newPosition = clamp(
Math.floor(positionY / DASHBOARD_CARD_HEIGHT),
0,
cardsCount - 1,
);
// if (newPosition !== positions.value[id]) {
// positions.value = objectMove(
// positions.value,
// positions.value[id],
// newPosition,
// );
// }
},
onFinish() {
top.value = positions.value[id] * DASHBOARD_CARD_HEIGHT;
runOnJS(setMoving)(false);
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
position: 'absolute',
left: 0,
right: 0,
top: top.value,
zIndex: moving ? 1 : 0,
shadowColor: 'black',
shadowOffset: {
height: 0,
width: 0,
},
shadowOpacity: withSpring(moving ? 0.2 : 0),
shadowRadius: 10,
};
}, [moving]);
return (
<Animated.View style={animatedStyle}>
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View>
<DashboardCard
position="relative"
h="100%"
w="100%"
clientCardType={clientCardType}
cardState={cardState}
headerTitle={headerTitle}
headerTitleColor={headerTitleColor}
gradientColors={gradientColors}
zIndex={2}
/>
</Animated.View>
</PanGestureHandler>
</Animated.View>
);
}
const DashboardCards: React.FC<DashboardCardsProps> = () => {
const { theme } = useTheme();
const [cardState, setCardState] = useState<string>('credit');
const positionsY = useSharedValue(listToObject(elementsArray));
const scrollY = useSharedValue(0);
const scrollViewRef = useAnimatedRef();
// TODO Calculate the top position based on the viewPort
const handleCardState = useCallback((type: string) => {
setCardState(type);
}, []);
useAnimatedReaction(
() => scrollY.value,
(scrolling) => scrollTo(scrollViewRef, 0, scrolling, false),
);
const handleScroll = useAnimatedScrollHandler((event) => {
scrollY.value = event.contentOffset.y;
});
return (
<Animated.ScrollView
ref={scrollViewRef}
contentContainerStyle={{
height: elementsArray.length * DASHBOARD_CARD_HEIGHT,
}}
onScroll={handleScroll}
scrollEventThrottle={16}
style={{
flex: 1,
position: 'relative',
}}
>
{elementsArray.map((card, index) => (
<MovableCard
id={card.id}
cardState={card.cardState}
headerTitle={card.headerTitle}
clientCardType={card.clientCardType}
headerTitleColor={card.headerTitleColor}
key={card.id}
gradientColors={card.gradientColors}
positions={positionsY}
scrollY={scrollY}
cardsCount={elementsArray.length}
/>
))}
</Animated.ScrollView>
);
};
export { DashboardCards };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment