Skip to content

Commit

Permalink
feat: useCurrentTabScrollY
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `useHeaderMeasurements` now returns
the `height` as an `Animated.SharedValue`
  • Loading branch information
andreialecu committed Jun 9, 2022
1 parent 90de549 commit 73ee5d7
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 9 deletions.
16 changes: 12 additions & 4 deletions example/src/AnimatedHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from 'react'
import { Text, StyleSheet, View } from 'react-native'
import { StyleSheet, View } from 'react-native'
import { useHeaderMeasurements } from 'react-native-collapsible-tab-view'
import Animated, {
interpolate,
useAnimatedStyle,
useDerivedValue,
} from 'react-native-reanimated'

import { useCurrentTabScrollY } from '../../src/hooks'
import ExampleComponent from './Shared/ExampleComponent'
import ReText from './Shared/ReText'
import { ExampleComponentType } from './types'

const title = 'Animated Header'
Expand All @@ -15,15 +18,20 @@ const MIN_HEADER_HEIGHT = 48

export const Header = () => {
const { top, height } = useHeaderMeasurements()
const scrollY = useCurrentTabScrollY()

const scrollYText = useDerivedValue(
() => `Scroll Y is: ${scrollY.value.toFixed(2)}`
)

const stylez = useAnimatedStyle(() => {
return {
transform: [
{
translateY: interpolate(
top.value,
[0, -(height - MIN_HEADER_HEIGHT)],
[0, (height - MIN_HEADER_HEIGHT) / 2]
[0, -(height.value || 0 - MIN_HEADER_HEIGHT)],
[0, (height.value || 0 - MIN_HEADER_HEIGHT) / 2]
),
},
],
Expand All @@ -33,7 +41,7 @@ export const Header = () => {
return (
<View style={[styles.root]}>
<Animated.View style={[styles.container, stylez]}>
<Text style={styles.text}>{title}</Text>
<ReText style={styles.text} text={scrollYText} />
</Animated.View>
</View>
)
Expand Down
6 changes: 5 additions & 1 deletion example/src/Shared/Contacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ const renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />
const ListEmptyComponent = () => {
const { top, height } = Tabs.useHeaderMeasurements()
const translateY = useDerivedValue(() => {
return interpolate(-top.value, [0, height], [-height / 2, 0])
return interpolate(
-top.value,
[0, height.value || 0],
[-(height.value || 0) / 2, 0]
)
}, [height])

const stylez = useAnimatedStyle(() => {
Expand Down
42 changes: 42 additions & 0 deletions example/src/Shared/ReText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// courtesy of https://github.com/wcandillon/react-native-redash/blob/fd0b0ddb3b4c10ae88cf1f8a95890c7c5eb3c475/src/ReText.tsx

import React from 'react'
import type { TextProps as RNTextProps } from 'react-native'
import { StyleSheet, TextInput } from 'react-native'
import Animated, { useAnimatedProps } from 'react-native-reanimated'

const styles = StyleSheet.create({
baseStyle: {
color: 'black',
},
})
Animated.addWhitelistedNativeProps({ text: true })

interface TextProps {
text: Animated.SharedValue<string>
style?: Animated.AnimateProps<RNTextProps>['style']
}

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)

const ReText = (props: TextProps) => {
const { text, style } = { style: {}, ...props }
const animatedProps = useAnimatedProps(() => {
return {
text: text.value,
// Here we use any because the text prop is not available in the type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any
})
return (
<AnimatedTextInput
underlineColorAndroid="transparent"
editable={false}
value={text.value}
style={[styles.baseStyle, style]}
{...{ animatedProps }}
/>
)
}

export default ReText
6 changes: 5 additions & 1 deletion example/src/Shared/SectionContacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,11 @@ const renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />
const ListEmptyComponent = () => {
const { top, height } = Tabs.useHeaderMeasurements()
const translateY = useDerivedValue(() => {
return interpolate(-top.value, [0, height], [-height / 2, 0])
return interpolate(
-top.value,
[0, height.value || 0],
[-(height.value || 0) / 2, 0]
)
}, [height])

const stylez = useAnimatedStyle(() => {
Expand Down
1 change: 1 addition & 0 deletions src/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ export const Container = React.memo(
tabName: tabNames.value[i],
})
index.value = i
scrollYCurrent.value = scrollY.value[index.value] || 0
}
},
[]
Expand Down
14 changes: 11 additions & 3 deletions src/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -574,19 +574,27 @@ interface HeaderMeasurements {
*/
top: Animated.SharedValue<number>
/**
* The height of the header
* Animated value that represents the height of the header
*/
height: number
height: Animated.SharedValue<number | undefined>
}

export function useHeaderMeasurements(): HeaderMeasurements {
const { headerTranslateY, headerHeight } = useTabsContext()
return {
top: headerTranslateY,
height: headerHeight.value || 0,
height: headerHeight,
}
}

/**
* Returns the vertical scroll position of the current tab as an Animated SharedValue
*/
export function useCurrentTabScrollY(): Animated.SharedValue<number> {
const { scrollYCurrent } = useTabsContext()
return scrollYCurrent
}

/**
* Returns the currently focused tab name
*/
Expand Down

0 comments on commit 73ee5d7

Please sign in to comment.