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> ); };
代码说明
- 将共享值改为数值类型
strikeThroughProgress,用0表示未完成(删除线隐藏),1表示已完成(删除线显示) - 使用
withTiming对数值进行动画,避免字符串解析错误 - 在动画样式中固定
textDecorationLine: 'line-through',通过textDecorationColor的透明度渐变实现删除线的显隐动画 - 可选添加文本颜色的灰度动画,让状态切换的视觉过渡更流畅
内容的提问来源于stack exchange,提问作者dev1ce
相关产品推荐
相关产品推荐

