Skip to content

Instantly share code, notes, and snippets.

@Stringsaeed
Created February 19, 2022 20:17
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 Stringsaeed/bc7dbea46cc97f433d3a797cfe7f7287 to your computer and use it in GitHub Desktop.
Save Stringsaeed/bc7dbea46cc97f433d3a797cfe7f7287 to your computer and use it in GitHub Desktop.
Animated Scroll Header context using react native reanimated
// Animated Scroll Header Context
// imports react and Animated
import React, {createContext, useContext} from 'react';
import {clamp} from 'react-native-redash';
import {NativeScrollEvent, NativeSyntheticEvent, ViewStyle} from 'react-native';
import Animated, {
Extrapolate,
interpolate,
useAnimatedScrollHandler,
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated';
// context type
type AnimatedScrollHeaderContextType = {
scrollY?: Animated.SharedValue<number>;
onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
headerStyle: Animated.AnimateStyle<ViewStyle>;
};
// provider props interface
interface Props {
children: React.ReactNode;
headerHeight: number;
}
export interface AnimatedScrollHeaderProps extends Props {}
// creates a context
export const AnimatedScrollHeaderContext =
createContext<AnimatedScrollHeaderContextType>({
onScroll: () => {},
headerStyle: {},
});
// creates a hook to access the context
export const useAnimatedScrollHeader = () => {
const context = useContext(AnimatedScrollHeaderContext);
if (!context) {
throw new Error(
'useAnimatedScrollHeaderContext must be used within a AnimatedScrollHeaderContextProvider',
);
}
return context;
};
// creates a provider
export const AnimatedScrollHeaderProvider: React.FC<Props> = ({
children,
headerHeight,
}) => {
const scrollY = useSharedValue(0);
const onScroll = useAnimatedScrollHandler<{prevY: number}>(
{
onScroll: (event, ctx) => {
const diff = event.contentOffset.y - ctx.prevY;
scrollY.value = clamp(scrollY.value + diff, 0, headerHeight);
},
onBeginDrag: (event, ctx) => {
ctx.prevY = event.contentOffset.y;
},
},
[],
);
const headerStyle = useAnimatedStyle(
() => ({
opacity: interpolate(scrollY.value, [0, 15], [1, 0], Extrapolate.CLAMP),
transform: [
{
translateY: interpolate(
scrollY.value,
[0, 15],
[0, -headerHeight],
Extrapolate.CLAMP,
),
},
],
}),
[headerHeight],
);
return (
<AnimatedScrollHeaderContext.Provider
value={{scrollY, onScroll, headerStyle}}>
{children}
</AnimatedScrollHeaderContext.Provider>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment