我正在尝试为我的博览会应用程序创建动画渐变。我知道这可以为使用 pure CSS:
的网站完成.container {
background: linear-gradient(45deg, "red", "green", "blue", "yellow")
animation: color 12s ease-in-out infinite
}
但是我不知道如何在 React Native 中做到这一点。我最初使用 expo-linear-gradient 来渲染线性渐变,但显然该包不能用于创建动画,所以我切换到 React Native Skia(带有 Reanimated)。我尝试了好几个小时,但仍然无法达到那种效果。而且我在网上找不到任何东西。
有人可以提示如何实现这一点吗?
动画是react-native与react in有很大不同的一件事。我建议使用react-native-reanimated来制作动画。使用 React Native Skia 来实现渐变动画似乎是正确的举措。我尝试使用 reanimated 的
createAnimatedComponent
来实现 expo-linear-gradient,但无法正常工作,所以我使用了 React Native Skia。大多数 Skia 组件都接受 SharedValue
,因此对它们进行动画处理只是对您的值进行重新动画处理:
import {
colorManipulators,
} from "@phantom-factotum/colorutils";
import {
Canvas,
LinearGradient,
Rect,
vec
} from '@shopify/react-native-skia';
import { ReactNode, useEffect, useMemo, useState } from 'react';
import { LayoutRectangle, StyleSheet, View, ViewStyle } from 'react-native';
import { interpolateColor, useDerivedValue, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated';
type Props = {
contentContainerStyle?: ViewStyle;
children: ReactNode;
colors: string[];
start:[number,number]
end:[number,number]
// style?:ViewStyle;
};
export default function AnimatedGradient({
contentContainerStyle,
children,
colors,
start,
end
}: Props) {
// store children layout properties
const [layout, setLayout] = useState<LayoutRectangle>({
width: 0,
height: 0,
x: 0,
y: 0,
});
const animValue = useSharedValue(0)
const darkColors = useMemo(()=>colors.map(color=>colorManipulators.blend(color,'black',0.5)),[colors])
const animatedColors = useDerivedValue(()=>{
return colors.map((color,i)=>interpolateColor(animValue.value,[0,1],[color,darkColors[i]]))
})
useEffect(()=>{
animValue.value = withRepeat(
withTiming(1,{duration:500}),
-1,
true
)
},[])
return (
<>
<Canvas
style={{
// Canvas can only have skia elements within it
// so position it absolutely and place non-skia elements
// on top of it
position: 'absolute',
width:layout.width,
height:layout.height
}}>
<Rect x={0} y={0} width={layout.width} height={layout.height} strokeWidth={1}>
<LinearGradient
colors={animatedColors}
origin={vec(layout.width/2, layout.height/2)}
start={vec(layout.width*start[0],layout.height*start[1])}
end={vec(layout.width*end[0],layout.height*end[1])}
/>
</Rect>
</Canvas>
<View
style={styles.contentContainer}
onLayout={(e) => setLayout(e.nativeEvent.layout)}>
{children}
</View>
</>
);
}
const styles = StyleSheet.create({
contentContainer: {
backgroundColor: 'transparent',
},
});