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

React Native Reanimated2实现Todo文本删除线动画遇错求助

React Native Reanimated2 Todo删除线动画实现方案

问题说明

我正在学习Reanimated2,搭建简易Todo应用,想要在切换Todo完成状态时给文本添加删除线的动画效果,但实现后出现报错。代码及报错信息如下:

原代码

const TodoItem = ({ todo }) => {
  const { toggleTodo } = useTodoStore((state) => state);
  const progress = useSharedValue('none');

  useEffect(() => {
    progress.value = withTiming(todo.completed ? 'line-through' : 'none', {
        duration: 1000,
        easing: Easing.linear,
    })
  }, [todo.completed]);

  const textReanimatedStyle = useAnimatedStyle(() => ({
    textDecorationLine: progress.value, // ts error: Type 'string' is not assignable to type 'number | "none" | "underline" | "line-through" | "underline line-through" | undefined'.
  }), []);

  const toggleTodoHandler = () => {
    toggleTodo(todo.id);
  };

  return (
    <Animated.View
      style={styles.container}
      entering={FadeIn}
      exiting={FadeOut}
      layout={Layout.delay(300)}>
      <View style={styles.innerContainer}>
        <TouchableOpacity
          style={styles.checkboxContainer}
          activeOpacity={0.6}
          onPress={toggleTodoHandler}>
          {todo.completed ? (
            <Ionicon name="checkmark" size={20} color={'gray'} />
          ) : null}
        </TouchableOpacity>
        <Animated.Text
          numberOfLines={2}
          style={[
            styles.text,
            textReanimatedStyle,
          ]}>
          {todo.text}
        </Animated.Text>
      </View>
    </Animated.View>
  );
};

报错信息(翻译后)

无效的RCTTextDecorationLineType 'noneNaN'。有效值应为以下之一:(
  "line-through",
  none,
  underline,
  "underline line-through"
)

问题原因

Reanimated的withTiming是针对数值类型的动画工具,无法直接对字符串类型的样式属性(比如textDecorationLine的字符串值)进行动画。当你尝试传入字符串时,内部会尝试将其转换为数值,导致得到NaN,最终拼接出noneNaN这种无效值,触发报错。

解决方案

改用数值类型的共享值驱动动画,通过动态控制删除线的透明度实现渐变效果,以下是简洁的实现方式:

修改后的代码

const TodoItem = ({ todo }) => {
  const { toggleTodo } = useTodoStore((state) => state);
  // 用数值0(未完成)/1(已完成)作为动画驱动值
  const strikeThroughProgress = useSharedValue(0);

  useEffect(() => {
    // 根据todo状态动画到对应数值
    strikeThroughProgress.value = withTiming(todo.completed ? 1 : 0, {
        duration: 1000,
        easing: Easing.linear,
    })
  }, [todo.completed]);

  const textReanimatedStyle = useAnimatedStyle(() => ({
    // 固定设置删除线样式,通过透明度控制显示/隐藏
    textDecorationLine: 'line-through',
    // 根据进度动态调整删除线的透明度
    textDecorationColor: `rgba(128, 128, 128, ${strikeThroughProgress.value})`,
    // 可选:同时给文本添加灰度动画,让过渡更自然
    color: todo.completed 
      ? 'gray' 
      : `rgba(0, 0, 0, ${1 - strikeThroughProgress.value})`,
  }), []);

  const toggleTodoHandler = () => {
    toggleTodo(todo.id);
  };

  return (
    <Animated.View
      style={styles.container}
      entering={FadeIn}
      exiting={FadeOut}
      layout={Layout.delay(300)}>
      <View style={styles.innerContainer}>
        <TouchableOpacity
          style={styles.checkboxContainer}
          activeOpacity={0.6}
          onPress={toggleTodoHandler}>
          {todo.completed ? (
            <Ionicon name="checkmark" size={20} color={'gray'} />
          ) : null}
        </TouchableOpacity>
        <Animated.Text
          numberOfLines={2}
          style={[
            styles.text,
            textReanimatedStyle,
          ]}>
          {todo.text}
        </Animated.Text>
      </View>
    </Animated.View>
  );
};

代码说明

  1. 将共享值改为数值类型strikeThroughProgress,用0表示未完成(删除线隐藏),1表示已完成(删除线显示)
  2. 使用withTiming对数值进行动画,避免字符串解析错误
  3. 在动画样式中固定textDecorationLine: 'line-through',通过textDecorationColor的透明度渐变实现删除线的显隐动画
  4. 可选添加文本颜色的灰度动画,让状态切换的视觉过渡更流畅

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 19:06:25