如何在React Native中创建动画渐变?

问题描述 投票:0回答:1

我正在尝试为我的博览会应用程序创建动画渐变。我知道这可以为使用 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-native-reanimated
1个回答
0
投票

动画是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',
  },
});

© www.soinside.com 2019 - 2024. All rights reserved.