React Native中Reanimated3的SharedTransitionTag失效问题(Expo51)
问题:Expo 51 + Reanimated 3 共享元素转场异常
在iPhone的Expo Go环境下,使用React Native结合Reanimated 3的sharedTransitionTag实现屏幕间共享元素转场时,出现以下问题:
- 无预期的转场动画效果
- 返回上一屏幕时,图片会从顶部突然消失
已验证两种路由方案(Expo Router、React-Navigation NativeStack),结果一致;将他人可正常运行的Expo 49示例代码升级到Expo 51后,同样出现该问题,推测是依赖版本兼容性导致。
相关代码
Screen 1
import Animated from "react-native-reanimated"; import { useRouter } from 'expo-router'; import { View, Text, Pressable } from 'react-native'; export default function Test() { const router = useRouter(); return ( <View> <Text>Test</Text> <Animated.Image source={require('./../../assets/ovelser/1-deadlift.png')} style={{height: 200, width: 200}} sharedTransitionTag="plis" /> <Pressable onPress={() => router.push("/testend/1")} style={{backgroundColor: 'red', padding: 10, borderRadius: 5, marginTop: 10}} > <Text>Test</Text> </Pressable> </View> ); }
Screen 2
import Animated from "react-native-reanimated"; import { View, Text } from 'react-native'; export default function Testend() { return ( <View> <Text>Test</Text> <Animated.Image source={require('./../../assets/ovelser/1-deadlift.png')} style={{height: 400, width: 400, top: 500}} sharedTransitionTag="plis" /> </View> ); }
依赖列表
"dependencies": { "expo": "~51.0.20", "expo-constants": "~16.0.2", "expo-linking": "~6.3.1", "expo-router": "~3.5.18", "expo-status-bar": "~1.12.1", "frontend": "file:", "react": "18.2.0", "react-native": "^0.74.3", "react-native-countdown-circle-timer": "^3.2.1", "react-native-gesture-handler": "~2.16.1", "react-native-pager-view": "^6.3.0", "react-native-paper": "^5.12.3", "react-native-reanimated": "~3.10.1", "react-native-safe-area-context": "^4.10.1", "react-native-screens": "3.31.1", "react-native-shared-element": "^0.8.9" },
可能的修复方案
1. 调整Reanimated版本
Expo 51对应React Native 0.74.x,Reanimated 3.10.1可能在Expo Go环境存在sharedTransitionTag的适配bug。建议:
- 降级Reanimated到
~3.8.0(Expo 51初期推荐兼容版本),执行:npx expo install react-native-reanimated@~3.8.0 --fix - 或升级到Reanimated最新测试版,查看是否修复该问题。
2. 修改布局属性
Screen 2中图片使用top: 500绝对定位,可能导致Reanimated无法正确计算过渡路径。改用marginTop替代:
// Screen 2的Image style修改为 style={{height: 400, width: 400, marginTop: 500}}
3. 配置路由的Reanimated支持
对于Expo Router
在_layout.tsx中用Animated包裹Stack组件,确保转场动画能被Reanimated处理:
import { Stack } from 'expo-router'; import Animated from 'react-native-reanimated'; const AnimatedStack = Animated.createAnimatedComponent(Stack); export default function RootLayout() { return <AnimatedStack />; }
对于React-Navigation NativeStack
禁用默认导航动画,避免与共享元素转场冲突:
import { createNativeStackNavigator } from '@react-navigation/native-stack'; const Stack = createNativeStackNavigator(); function AppNavigator() { return ( <Stack.Navigator screenOptions={{ animation: 'none' }}> <Stack.Screen name="Test" component={Test} /> <Stack.Screen name="Testend" component={Testend} /> </Stack.Navigator> ); }
替代方案
1. 自定义Reanimated转场动画
手动控制动画逻辑,不受sharedTransitionTag限制:
- 在两个屏幕中用
Animated.View包裹图片 - 通过路由参数或全局状态传递元素的初始位置、大小
- 使用
useAnimatedStyle结合withTiming实现位置、大小的平滑过渡
2. 使用react-native-shared-element手动触发转场
虽然react-navigation-shared-element已废弃,但react-native-shared-element本身仍可使用:
- 用
SharedElement包裹需要转场的图片,设置唯一id:import { SharedElement } from 'react-native-shared-element'; // Screen 1 <SharedElement id="plis"> <Image source={...} style={...} /> </SharedElement> // Screen 2 <SharedElement id="plis"> <Image source={...} style={...} /> </SharedElement> - 在路由跳转时,手动调用转场方法(需结合导航生命周期监听)
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

