Skip to content

Instantly share code, notes, and snippets.

@kibolho
Last active June 6, 2024 13:23
Show Gist options
  • Select an option

  • Save kibolho/4bf58d7260b6be17d6856147de6e340f to your computer and use it in GitHub Desktop.

Select an option

Save kibolho/4bf58d7260b6be17d6856147de6e340f to your computer and use it in GitHub Desktop.
useAnimatedCollapse
import Animated, { SharedValue, interpolate, useAnimatedStyle } from 'react-native-reanimated';
import CaretUp from '~/assets/images/icons/CaretUp';
export const CaretAnimated = ({
isCollapsible,
hidden,
}: {
isCollapsible: SharedValue<number>;
hidden?: boolean;
}) => {
const rotationAnimatedStyle = useAnimatedStyle(() => {
const rotation = interpolate(isCollapsible.value, [1, 0], [0, -180]);
return { transform: [{ rotate: `${rotation}deg` }] };
});
if (hidden) {
return null;
}
return (
<Animated.View style={rotationAnimatedStyle}>
<CaretUp />
</Animated.View>
);
};
export const Home = () => {
const { toggleButton, bodyHeight, setBodySectionHeight, isCollapsible } = useAnimatedCollapse({
startExpanded: true,
});
return (
<Box style={styles.container}>
<PressableCustom onPress={toggleButton} hitSlop={16} style={styles.headerContainer}>
<Box style={styles.headerBody}>
Title
</Box>
<CaretAnimated isCollapsible={isCollapsible} hidden={!!exampleCard} />
</PressableCustom>
{shouldRenderContent && (
<AnimatedWrapper bodyHeight={bodyHeight} setBodySectionHeight={setBodySectionHeight}>
<Box style={styles.contentContainer}>
/// body
</Box>
</AnimatedWrapper>
)}
</Box>
);
};
import { useState } from 'react';
import {
Easing,
interpolate,
useAnimatedStyle,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
export const useAnimatedCollapse = ({
isNotExpandable,
startExpanded,
onClose,
}: {
isNotExpandable?: boolean;
startExpanded?: boolean;
onClose?: () => void;
}) => {
// start animation logic
const sharedValue = useSharedValue(isNotExpandable || startExpanded ? 1 : 0);
const [bodySectionHeight, setBodySectionHeight] = useState(0);
const bodyHeight = useAnimatedStyle(() => ({
height: interpolate(sharedValue.value, [0, 1], [0, bodySectionHeight]),
}));
const toggleButton = () => {
if (isNotExpandable) {
return;
}
if (sharedValue.value === 0) {
sharedValue.value = withTiming(1, {
duration: 300,
easing: Easing.bezier(0.4, 0.0, 0.2, 1),
});
} else {
sharedValue.value = withTiming(0, {
duration: 300,
easing: Easing.bezier(0.4, 0.0, 0.2, 1),
});
onClose?.();
}
};
// end animation logic
return { toggleButton, bodyHeight, setBodySectionHeight, isCollapsible: sharedValue };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment