如何使用Reanimated 2实现React Native底部Tab栏图标动画?
问题分析与解决方案
你的代码存在两个核心问题:
- 动画样式
animateIcon未关联当前选中的Tab状态,无论是否选中都会执行向左的弹簧动画,且所有Tab共用同一静态动画,切换时无法触发反向恢复动画。 useAnimatedStyle未依赖currentRouteIndex,状态更新时动画不会重新计算。
以下是修正后的实现:
1. 引入共享值跟踪选中状态
用Reanimated的useSharedValue创建响应式变量,实时同步当前选中的Tab ID:
import { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated'; // 初始化共享值为当前选中的路由索引 const activeTabId = useSharedValue(currentRouteIndex);
2. 切换Tab时更新共享值
在点击回调里更新共享值,触发动画过渡:
const handleTabPress = (name, id) => { onPress(name, id); // 保留原有业务逻辑 activeTabId.value = id; // 更新共享值,触发动画 };
3. 为每个Tab生成独立动画样式
修改动画样式生成逻辑,让每个Tab根据自身ID和选中状态计算位移:
const getAnimatedStyle = (tabId) => { return useAnimatedStyle(() => { return { transform: [ { translateX: withSpring( activeTabId.value === tabId ? -15 : 0, { damping: 15, stiffness: 100 } // 可根据需求调整弹簧参数 ) } ] }; }, [tabId]); };
4. 渲染Tab按钮时应用动画
遍历Tabs时为每个Tab绑定专属的动画样式:
const renderButtons = useMemo(() => { return tabs.map((tab) => { const animatedStyle = getAnimatedStyle(tab.id); return ( <Box key={tab.id} alignItems='center' flexDirection='column' style={styles.overlay} > <TouchableWithoutFeedback onPress={() => handleTabPress(tab.name, tab.id)} style={styles.button} > <AnimatedBox style={animatedStyle}> <Home fill={'#000'} size={20} /> </AnimatedBox> </TouchableWithoutFeedback> </Box> ); }); }, [activeTabId, styles.button, styles.overlay, tabs]);
关键改动说明
- 用
useSharedValue替代普通状态,让Reanimated能监听状态变化并驱动动画。 - 每个Tab拥有独立的动画样式,根据自身ID和选中状态动态计算位移值。
- 点击Tab时更新共享值,触发弹簧动画的正向/反向平滑过渡。
内容的提问来源于stack exchange,提问作者Ash Archin
相关产品推荐
相关产品推荐

