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

如何使用React Native Reanimated v2实现多个列表项的交互动画

问题原因分析
  • 动画值progress无重置逻辑:首次点击触发动画后progress值永久为1,后续选中状态变更时withTiming(1)没有数值差,无法触发动画
  • 子组件选中状态未和父组件同步:父组件传入了全局selectedItem状态,但子组件单独维护内部selected状态,会导致多列表项选中状态冲突
  • 直接卸载动画组件:选中状态为false时直接销毁Animated.View,不仅无法触发退场动画,也可能导致下次渲染时动画状态异常
修复方案

1. 父组件点击逻辑补充

先保证父组件的selectItem逻辑支持点击选中、再次点击取消选中:

const selectItem = (item) => {
  setSelectedItem(prev => prev?._id === item._id ? null : item)
}

2. 子组件(Item Component)完整修改代码

// 去掉内部冗余的selected useState,直接和父组件状态同步
const selected = selectedItem?._id === item._id;
const [count, setCount] = useState(1);
    
// Animation
const progress = useSharedValue(0);

const reAnimatedStyle = useAnimatedStyle(() => {
  return {
    opacity: progress.value,
    transform: [{scale: progress.value}],
    // 动画未触发时禁止点击,避免幽灵交互
    pointerEvents: progress.value === 0 ? 'none' : 'auto'
  };
});

useEffect(() => {
  // 选中时动画到1,取消选中时动画回0
  progress.value = withTiming(selected ? 1 : 0, {duration: 2000});
}, [selected]);

return (
  <TouchableOpacity
    onPress={() => setSelectedItem(item)}
    style={[globalStyle.pageContainer]}
  >
    {/* 去掉条件渲染,保留组件让动画完整执行 */}
    <Animated.View
      style={[
        {flexDirection: 'row', alignItems: 'center'},
        reAnimatedStyle,
      ]}
    >
      ...
    </Animated.View>
  </TouchableOpacity>
)

修复说明

  • 移除了子组件内部的selected状态,直接和父组件传入的全局选中状态同步,避免多列表项状态冲突
  • useEffect中根据选中状态正反执行动画,取消选中时会自动把progress重置为0,下次选中时就会重新触发从0到1的入场动画
  • 去掉了Animated.View的条件渲染逻辑,靠动画样式的opacity和pointerEvents控制显隐,保证入场、退场动画都能正常执行

内容的提问来源于stack exchange,提问作者Kerry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 08:06:04