Use scale animation for tabs (#5483)

* fix passing PressableScale oPressIn prop

* use PressableScale for tabs
This commit is contained in:
Samuel Newman
2024-09-25 18:28:10 +01:00
committed by GitHub
parent 47301661f7
commit 498f957a1d
2 changed files with 26 additions and 17 deletions
+16 -11
View File
@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {Pressable, PressableProps} from 'react-native' import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native'
import Animated, { import Animated, {
cancelAnimation, cancelAnimation,
runOnJS, runOnJS,
@@ -16,14 +16,17 @@ const DEFAULT_TARGET_SCALE = isNative || isTouchDevice ? 0.98 : 1
export function PressableScale({ export function PressableScale({
targetScale = DEFAULT_TARGET_SCALE, targetScale = DEFAULT_TARGET_SCALE,
children, children,
contentContainerStyle,
onPressIn,
onPressOut,
...rest ...rest
}: {targetScale?: number} & Exclude< }: {
PressableProps, targetScale?: number
'onPressIn' | 'onPressOut' contentContainerStyle?: StyleProp<ViewStyle>
>) { } & Exclude<PressableProps, 'onPressIn' | 'onPressOut'>) {
const scale = useSharedValue(1) const scale = useSharedValue(1)
const style = useAnimatedStyle(() => ({ const animatedStyle = useAnimatedStyle(() => ({
transform: [{scale: scale.value}], transform: [{scale: scale.value}],
})) }))
@@ -32,22 +35,24 @@ export function PressableScale({
accessibilityRole="button" accessibilityRole="button"
onPressIn={e => { onPressIn={e => {
'worklet' 'worklet'
if (rest.onPressIn) { if (onPressIn) {
runOnJS(rest.onPressIn)(e) runOnJS(onPressIn)(e)
} }
cancelAnimation(scale) cancelAnimation(scale)
scale.value = withTiming(targetScale, {duration: 100}) scale.value = withTiming(targetScale, {duration: 100})
}} }}
onPressOut={e => { onPressOut={e => {
'worklet' 'worklet'
if (rest.onPressOut) { if (onPressOut) {
runOnJS(rest.onPressOut)(e) runOnJS(onPressOut)(e)
} }
cancelAnimation(scale) cancelAnimation(scale)
scale.value = withTiming(1, {duration: 100}) scale.value = withTiming(1, {duration: 100})
}} }}
{...rest}> {...rest}>
<Animated.View style={style}>{children as React.ReactNode}</Animated.View> <Animated.View style={[animatedStyle, contentContainerStyle]}>
{children as React.ReactNode}
</Animated.View>
</Pressable> </Pressable>
) )
} }
+10 -6
View File
@@ -1,5 +1,5 @@
import React, {ComponentProps} from 'react' import React, {ComponentProps} from 'react'
import {GestureResponderEvent, TouchableOpacity, View} from 'react-native' import {GestureResponderEvent, View} from 'react-native'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
@@ -8,6 +8,7 @@ import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
import {StackActions} from '@react-navigation/native' import {StackActions} from '@react-navigation/native'
import {useAnalytics} from '#/lib/analytics/analytics' import {useAnalytics} from '#/lib/analytics/analytics'
import {PressableScale} from '#/lib/custom-animations/PressableScale'
import {useHaptics} from '#/lib/haptics' import {useHaptics} from '#/lib/haptics'
import {useDedupe} from '#/lib/hooks/useDedupe' import {useDedupe} from '#/lib/hooks/useDedupe'
import {useMinimalShellFooterTransform} from '#/lib/hooks/useMinimalShellTransform' import {useMinimalShellFooterTransform} from '#/lib/hooks/useMinimalShellTransform'
@@ -29,6 +30,7 @@ import {Text} from '#/view/com/util/text/Text'
import {UserAvatar} from '#/view/com/util/UserAvatar' import {UserAvatar} from '#/view/com/util/UserAvatar'
import {Logo} from '#/view/icons/Logo' import {Logo} from '#/view/icons/Logo'
import {Logotype} from '#/view/icons/Logotype' import {Logotype} from '#/view/icons/Logotype'
import {atoms as a} from '#/alf'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {SwitchAccountDialog} from '#/components/dialogs/SwitchAccount' import {SwitchAccountDialog} from '#/components/dialogs/SwitchAccount'
import { import {
@@ -326,7 +328,7 @@ export function BottomBar({navigation}: BottomTabBarProps) {
interface BtnProps interface BtnProps
extends Pick< extends Pick<
ComponentProps<typeof TouchableOpacity>, ComponentProps<typeof PressableScale>,
| 'accessible' | 'accessible'
| 'accessibilityRole' | 'accessibilityRole'
| 'accessibilityHint' | 'accessibilityHint'
@@ -350,7 +352,7 @@ function Btn({
accessibilityLabel, accessibilityLabel,
}: BtnProps) { }: BtnProps) {
return ( return (
<TouchableOpacity <PressableScale
testID={testID} testID={testID}
style={styles.ctrl} style={styles.ctrl}
onPress={onLongPress ? onPress : undefined} onPress={onLongPress ? onPress : undefined}
@@ -358,13 +360,15 @@ function Btn({
onLongPress={onLongPress} onLongPress={onLongPress}
accessible={accessible} accessible={accessible}
accessibilityLabel={accessibilityLabel} accessibilityLabel={accessibilityLabel}
accessibilityHint={accessibilityHint}> accessibilityHint={accessibilityHint}
targetScale={0.8}
contentContainerStyle={[a.flex_1]}>
{icon} {icon}
{notificationCount ? ( {notificationCount ? (
<View style={[styles.notificationCount]}> <View style={[styles.notificationCount, {top: -5}]}>
<Text style={styles.notificationCountLabel}>{notificationCount}</Text> <Text style={styles.notificationCountLabel}>{notificationCount}</Text>
</View> </View>
) : undefined} ) : undefined}
</TouchableOpacity> </PressableScale>
) )
} }