React Native中Reanimated与Skia线性渐变动画失效求助
问题
尝试用React Native Reanimated和Skia实现线性渐变的颜色过渡动画,但动画完全无法运行,点击按钮触发过渡也没有效果。
使用版本:
react-native-skia: 1.7.6react-native-reanimated: 3.16.0
相关代码:
export default function App() { const startColor = useSharedValue('rgb(255, 219, 128)'); const endColor = useSharedValue('rgb(218, 78, 90)'); const colors = useDerivedValue(() => { return [startColor.value, endColor.value]; }); const duration = 1000; const easing = Easing.bezier(0.25, -0.5, 0.25, 1); useEffect(() => { startColor.value = withRepeat( withTiming('rgb(255, 219, 128)', { duration, easing }), -1, true ); endColor.value = withRepeat( withTiming('rgb(218, 78, 90)', { duration, easing }), -1, true ); }, []); return ( <View style={{flex: 1}}> <Canvas style={{ flex: .6, justifyContent: 'center', alignItems: 'center' }} > <Rect x={50} y={150} width={300} height={300}> <LinearGradient start={vec(0, 0)} end={vec(300, 0)} colors={colors.value} /> </Rect> </Canvas> </View> ); }
解决方案
问题根源
- Skia组件属性不支持直接监听共享值:React Native Skia的
LinearGradient无法自动响应Reanimated共享值/派生值的变化,必须通过专门的动画化属性绑定来驱动更新。 - 字符串颜色的动画兼容性问题:Reanimated对数值类型的动画处理更稳定,字符串格式的RGB值可能无法被正确解析为可动画参数。
- 目标颜色配置错误:原代码中
withTiming的目标颜色与初始值完全一致,导致没有视觉上的颜色过渡效果。
修复后的代码
import React, { useEffect } from 'react'; import { View, Button } from 'react-native'; import { Canvas, Rect, LinearGradient, vec } from '@shopify/react-native-skia'; import { useSharedValue, withRepeat, withTiming, Easing, useAnimatedProps } from 'react-native-reanimated'; export default function App() { // 用数值数组存储RGB通道值,提升动画精度 const startColor = useSharedValue([255, 219, 128]); const endColor = useSharedValue([218, 78, 90]); const duration = 1000; const easing = Easing.bezier(0.25, -0.5, 0.25, 1); // 创建Skia可识别的动画化属性 const animatedGradientProps = useAnimatedProps(() => ({ colors: [ `rgb(${startColor.value.join(',')})`, `rgb(${endColor.value.join(',')})`, ], })); // 自动触发动画 useEffect(() => { startColor.value = withRepeat( withTiming([218, 78, 90], { duration, easing }), -1, true ); endColor.value = withRepeat( withTiming([255, 219, 128], { duration, easing }), -1, true ); }, []); // 按钮触发动画的回调 const triggerAnimation = () => { startColor.value = withRepeat( withTiming([218, 78, 90], { duration, easing }), -1, true ); endColor.value = withRepeat( withTiming([255, 219, 128], { duration, easing }), -1, true ); }; return ( <View style={{ flex: 1, paddingTop: 50 }}> <Button title="触发颜色过渡" onPress={triggerAnimation} /> <Canvas style={{ flex: 0.6, marginTop: 20 }}> <Rect x={50} y={150} width={300} height={300}> <LinearGradient start={vec(0, 0)} end={vec(300, 0)} animatedProps={animatedGradientProps} /> </Rect> </Canvas> </View> ); }
关键修改说明
- 颜色格式转换:将字符串RGB改为数值数组,让Reanimated能独立处理每个颜色通道的过渡动画,避免字符串解析问题。
- 动画属性绑定:使用
useAnimatedProps生成LinearGradient可识别的动态属性,确保组件能实时响应共享值变化。 - 修正目标颜色:调整
withTiming的目标值,实现两种颜色的双向循环过渡。 - 移除无效样式:删除Canvas的
justifyContent和alignItems,Canvas采用基于左上角的坐标系统,这些布局属性无效。
内容的提问来源于stack exchange,提问作者wind_kind
相关产品推荐
相关产品推荐

