跳转到主要内容

动画

React Native Skia 提供了与 Reanimated v3 及以上版本的集成,从而可以在 UI 线程上执行动画。

React Native Skia 支持直接将 Reanimated 的共享值和派生值用作属性。 不需要像 createAnimatedComponentuseAnimatedProps 这样的函数;只需将 Reanimated 值直接作为属性传递即可。

tsx
import {useEffect} from "react";
import {Canvas, Circle, Group} from "@shopify/react-native-skia";
import {
useDerivedValue,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
 
export const HelloWorld = () => {
const size = 256;
const r = useSharedValue(0);
const c = useDerivedValue(() => size - r.value);
useEffect(() => {
r.value = withRepeat(withTiming(size * 0.33, { duration: 1000 }), -1);
}, [r, size]);
return (
<Canvas style={{ flex: 1 }}>
<Group blendMode="multiply">
<Circle cx={r} cy={r} r={r} color="cyan" />
<Circle cx={c} cy={r} r={r} color="magenta" />
<Circle
cx={size/2}
cy={c}
r={r}
color="yellow"
/>
</Group>
</Canvas>
);
};
tsx
import {useEffect} from "react";
import {Canvas, Circle, Group} from "@shopify/react-native-skia";
import {
useDerivedValue,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
 
export const HelloWorld = () => {
const size = 256;
const r = useSharedValue(0);
const c = useDerivedValue(() => size - r.value);
useEffect(() => {
r.value = withRepeat(withTiming(size * 0.33, { duration: 1000 }), -1);
}, [r, size]);
return (
<Canvas style={{ flex: 1 }}>
<Group blendMode="multiply">
<Circle cx={r} cy={r} r={r} color="cyan" />
<Circle cx={c} cy={r} r={r} color="magenta" />
<Circle
cx={size/2}
cy={c}
r={r}
color="yellow"
/>
</Group>
</Canvas>
);
};

我们提供了一些 Skia 特定的动画钩子,特别是针对路径的。

颜色

对于颜色,React Native Skia 使用与 Reanimated 不同的存储格式。这意味着 Reanimated 的 interpolateColor 无法直接使用。 相反,你可以使用 React Native Skia 的 interpolateColors

tsx
import {
Canvas,
LinearGradient,
Fill,
// Use this function instead of interpolateColor from Reanimated
interpolateColors,
vec,
} from "@shopify/react-native-skia";
import { useEffect } from "react";
import { useWindowDimensions } from "react-native";
import {
useDerivedValue,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
 
const startColors = [
"rgba(34, 193, 195, 0.4)",
"rgba(34,193,195,0.4)",
"rgba(63,94,251,1)",
"rgba(253,29,29,0.4)",
];
const endColors = [
"rgba(0,212,255,0.4)",
"rgba(253,187,45,0.4)",
"rgba(252,70,107,1)",
"rgba(252,176,69,0.4)",
];
 
export const AnimatedGradient = () => {
const { width, height } = useWindowDimensions();
const colorsIndex = useSharedValue(0);
useEffect(() => {
colorsIndex.value = withRepeat(
withTiming(startColors.length - 1, {
duration: 4000,
}),
-1,
true
);
}, []);
const gradientColors = useDerivedValue(() => {
return [
interpolateColors(colorsIndex.value, [0, 1, 2, 3], startColors),
interpolateColors(colorsIndex.value, [0, 1, 2, 3], endColors),
];
});
return (
<Canvas style={{ flex: 1 }}>
<Fill>
<LinearGradient
start={vec(0, 0)}
end={vec(width, height)}
colors={gradientColors}
/>
</Fill>
</Canvas>
);
};
tsx
import {
Canvas,
LinearGradient,
Fill,
// Use this function instead of interpolateColor from Reanimated
interpolateColors,
vec,
} from "@shopify/react-native-skia";
import { useEffect } from "react";
import { useWindowDimensions } from "react-native";
import {
useDerivedValue,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
 
const startColors = [
"rgba(34, 193, 195, 0.4)",
"rgba(34,193,195,0.4)",
"rgba(63,94,251,1)",
"rgba(253,29,29,0.4)",
];
const endColors = [
"rgba(0,212,255,0.4)",
"rgba(253,187,45,0.4)",
"rgba(252,70,107,1)",
"rgba(252,176,69,0.4)",
];
 
export const AnimatedGradient = () => {
const { width, height } = useWindowDimensions();
const colorsIndex = useSharedValue(0);
useEffect(() => {
colorsIndex.value = withRepeat(
withTiming(startColors.length - 1, {
duration: 4000,
}),
-1,
true
);
}, []);
const gradientColors = useDerivedValue(() => {
return [
interpolateColors(colorsIndex.value, [0, 1, 2, 3], startColors),
interpolateColors(colorsIndex.value, [0, 1, 2, 3], endColors),
];
});
return (
<Canvas style={{ flex: 1 }}>
<Fill>
<LinearGradient
start={vec(0, 0)}
end={vec(width, height)}
colors={gradientColors}
/>
</Fill>
</Canvas>
);
};