Created
February 19, 2022 20:17
-
-
Save Stringsaeed/bc7dbea46cc97f433d3a797cfe7f7287 to your computer and use it in GitHub Desktop.
Animated Scroll Header context using react native reanimated
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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