diff --git a/example/App.tsx b/example/App.tsx index 433b4eb..584b585 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -10,6 +10,7 @@ import 'react-native-gesture-handler'; import { DefaultHeaderScreen } from './src/DefaultHeaderScreen'; import { StickyHeaderScreen } from './src/StickyHeaderScreen'; import { BackgroundHeaderScreen } from './src/BackgroundHeaderScreen'; +import { BigHeaderScreen } from './src/BigHeaderScreen'; import { SubHeaderScreen } from './src/SubHeaderScreen'; import { CustomHeaderScreen, @@ -23,6 +24,7 @@ export type StackParamList = { DefaultHeader: undefined; StickyHeader: undefined; BackgroundHeader: undefined; + BigHeader: undefined; SubHeader: undefined; WithCustomHeader: undefined; CustomHeaderDetail: undefined; @@ -36,8 +38,9 @@ const samples: { title: string; routeName: keyof StackParamList }[] = [ { title: 'Sample 1-1: Default Header', routeName: 'DefaultHeader' }, { title: 'Sample 1-2: Sticky Header', routeName: 'StickyHeader' }, { title: 'Sample 1-3: Background Header', routeName: 'BackgroundHeader' }, - { title: 'Sample 2: Sub Header', routeName: 'SubHeader' }, - { title: 'Sample 3: Custom Header', routeName: 'WithCustomHeader' }, + { title: 'Sample 2: Big Header', routeName: 'BigHeader' }, + { title: 'Sample 3: Sub Header', routeName: 'SubHeader' }, + { title: 'Sample 4: Custom Header', routeName: 'WithCustomHeader' }, ]; function HomeScreen({ navigation }: ScreenProps) { @@ -106,7 +109,16 @@ function App() { }} /> - {/* Sample 2: Sub Header */} + {/* Sample 2: Big Header */} + + + {/* Sample 3: Sub Header */} - {/* Sample 3: Custom Header */} + {/* Sample 4: Custom Header */} ; +}; + +const BigHeaderScreen = ({ navigation }: ScreenProps) => { + const { + onScroll, + containerPaddingTop, + scrollIndicatorInsetTop, + } = useCollapsibleBigHeader({ + headerStyle: { + height: 250, + }, + headerBackground: ( + + + + ), + collapsedColor: 'white', + }); + + return ( + navigation.navigate('Detail'))} + keyExtractor={(item: any) => item.toString()} + /> + ); +}; + +export { BigHeaderScreen }; diff --git a/index.ts b/index.ts index b5ca8c5..2124d66 100644 --- a/index.ts +++ b/index.ts @@ -1,5 +1,6 @@ import { useCollapsibleHeader, + useCollapsibleBigHeader, useCollapsibleSubHeader, Collapsible, UseCollapsibleOptions, @@ -14,6 +15,7 @@ import { CollapsibleSubHeaderAnimator } from './src/CollapsibleSubHeaderAnimator export { useCollapsibleHeader, + useCollapsibleBigHeader, useCollapsibleSubHeader, setSafeBounceHeight, disableExpoTranslucentStatusBar, diff --git a/src/core.tsx b/src/core.tsx index 0deaf62..f2568d6 100644 --- a/src/core.tsx +++ b/src/core.tsx @@ -21,6 +21,7 @@ import { createCollapsibleCustomHeaderAnimator } from './createCollapsibleCustom enum CollapsibleHeaderType { Default, + BigHeader, SubHeader, } @@ -112,6 +113,10 @@ const useCollapsibleHeader = ( } } const safeBounceHeight = getSafeBounceHeight(); + const minHeaderVisibleHeight = + collapsibleHeaderType === CollapsibleHeaderType.BigHeader + ? getDefaultHeaderHeight(isLandscape) + : 0; const animatedDiffClampY = Animated.diffClamp( positionY, @@ -124,15 +129,19 @@ const useCollapsibleHeader = ( outputRange: [0, 1], extrapolate: 'clamp', }); - const translateY = Animated.multiply(progress, -headerHeight); + const heightMoveTo = -(headerHeight - minHeaderVisibleHeight); + const translateY = Animated.multiply(progress, heightMoveTo); const opacity = Animated.subtract(1, progress); - if (collapsibleHeaderType === CollapsibleHeaderType.Default) { + if ( + collapsibleHeaderType === CollapsibleHeaderType.Default || + collapsibleHeaderType === CollapsibleHeaderType.BigHeader + ) { const options = { headerStyle: { + ...headerStyle, transform: [{ translateY }], opacity, - ...headerStyle, }, headerBackground: createHeaderBackground({ translateY, @@ -144,11 +153,48 @@ const useCollapsibleHeader = ( }), headerTransparent: true, }; + if (customHeader) { Object.assign(options, { header: createCollapsibleCustomHeaderAnimator(customHeader), }); } + + if ( + headerBackground && + collapsibleHeaderType === CollapsibleHeaderType.BigHeader + ) { + const startToVisible = 0.5; + const defaultHeaderTranslateY = progress.interpolate({ + inputRange: [0, startToVisible, 1], + outputRange: [ + -1000, + heightMoveTo * startToVisible * 0.5, + heightMoveTo * 0.5, + ], + }); + const defaultHeaderOpacity = progress.interpolate({ + inputRange: [0, startToVisible, 1], + outputRange: [0, 0, 1], + }); + options.headerStyle = { + ...options.headerStyle, + opacity: defaultHeaderOpacity, + transform: [{ translateY: new Animated.Value(0) }], + }; + Object.assign(options, { + headerTitleStyle: { + transform: [{ translateY: defaultHeaderTranslateY }], + }, + headerLeftContainerStyle: { + transform: [{ translateY: defaultHeaderTranslateY }], + }, + headerRightContainerStyle: { + transform: [{ translateY: defaultHeaderTranslateY }], + }, + }); + } + navigation.setOptions(options); } @@ -180,7 +226,14 @@ const useCollapsibleHeader = ( ); }; +const useCollapsibleBigHeader = (options?: UseCollapsibleOptions) => + useCollapsibleHeader(options, CollapsibleHeaderType.BigHeader); + const useCollapsibleSubHeader = (options?: UseCollapsibleOptions) => useCollapsibleHeader(options, CollapsibleHeaderType.SubHeader); -export { useCollapsibleHeader, useCollapsibleSubHeader }; +export { + useCollapsibleHeader, + useCollapsibleBigHeader, + useCollapsibleSubHeader, +};