You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Reanimated 2实现React Native底部Tab栏图标动画?

问题分析与解决方案

你的代码存在两个核心问题:

  1. 动画样式animateIcon未关联当前选中的Tab状态,无论是否选中都会执行向左的弹簧动画,且所有Tab共用同一静态动画,切换时无法触发反向恢复动画。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:35:29