Hooks
以下是在将 React Native Skia 与 Reanimated 一起使用时我们提供的动画 hooks。我们还提供用于在与 Reanimated 集成时创建纹理的 hooks。
usePathInterpolation
此 hook 基于进度值在不同的路径值之间进行插值,从而在提供的路径之间提供平滑的过渡。
路径需要是可插值的,这意味着它们必须包含相同数量和类型的命令。如果路径具有不同的命令或不同数量的命令,则插值可能不会按预期运行。请确保 outputRange
数组中的所有路径的结构相似,以便进行正确的插值。为了插值两个完全不同的路径,我们发现 flubber 库 与 Skia 配合使用效果良好(请参阅示例)。
tsx
importReact , {useEffect } from 'react';import {useSharedValue ,withTiming } from 'react-native-reanimated';import {Skia ,usePathInterpolation ,Canvas ,Path } from '@shopify/react-native-skia';constangryPath =Skia .Path .MakeFromSVGString ("M 16 25 C 32 27 43 28 49 28 C 54 28 62 28 73 26 C 66 54 60 70 55 74 C 51 77 40 75 27 55 C 25 50 21 40 27 55 Z")!;constnormalPath =Skia .Path .MakeFromSVGString ("M 21 31 C 31 32 39 32 43 33 C 67 35 80 36 81 38 C 84 42 74 57 66 60 C 62 61 46 59 32 50 C 24 44 20 37 21 31 Z")!;constgoodPath =Skia .Path .MakeFromSVGString ("M 21 45 C 21 37 24 29 29 25 C 34 20 38 18 45 18 C 58 18 69 30 69 45 C 69 60 58 72 45 72 C 32 72 21 60 21 45 Z")!;constDemo = () => {constprogress =useSharedValue (0);useEffect (() => {progress .value =withTiming (1, {duration : 1000 });}, []);constpath =usePathInterpolation (progress , [0, 0.5, 1], [angryPath ,normalPath ,goodPath ]);return (<Canvas style ={{flex : 1 }}><Path path ={path }style ="stroke"strokeWidth ={5}strokeCap ="round"strokeJoin ="round" /></Canvas >);};
tsx
importReact , {useEffect } from 'react';import {useSharedValue ,withTiming } from 'react-native-reanimated';import {Skia ,usePathInterpolation ,Canvas ,Path } from '@shopify/react-native-skia';constangryPath =Skia .Path .MakeFromSVGString ("M 16 25 C 32 27 43 28 49 28 C 54 28 62 28 73 26 C 66 54 60 70 55 74 C 51 77 40 75 27 55 C 25 50 21 40 27 55 Z")!;constnormalPath =Skia .Path .MakeFromSVGString ("M 21 31 C 31 32 39 32 43 33 C 67 35 80 36 81 38 C 84 42 74 57 66 60 C 62 61 46 59 32 50 C 24 44 20 37 21 31 Z")!;constgoodPath =Skia .Path .MakeFromSVGString ("M 21 45 C 21 37 24 29 29 25 C 34 20 38 18 45 18 C 58 18 69 30 69 45 C 69 60 58 72 45 72 C 32 72 21 60 21 45 Z")!;constDemo = () => {constprogress =useSharedValue (0);useEffect (() => {progress .value =withTiming (1, {duration : 1000 });}, []);constpath =usePathInterpolation (progress , [0, 0.5, 1], [angryPath ,normalPath ,goodPath ]);return (<Canvas style ={{flex : 1 }}><Path path ={path }style ="stroke"strokeWidth ={5}strokeCap ="round"strokeJoin ="round" /></Canvas >);};
usePathValue
此 hook 提供了一种简单的方式来为路径设置动画。在后台,它确保一切都尽可能高效地完成。有一个可选的第二个参数可用于设置默认路径值。
tsx
import {useSharedValue ,withSpring } from "react-native-reanimated";import {Gesture ,GestureDetector } from "react-native-gesture-handler";import {usePathValue ,Canvas ,Path ,processTransform3d ,Skia } from "@shopify/react-native-skia";constrrct =Skia .Path .Make ();rrct .addRRect (Skia .RRectXY (Skia .XYWHRect (0, 0, 100, 100), 10, 10));export constFrostedCard = () => {constrotateY =useSharedValue (0);constgesture =Gesture .Pan ().onChange ((event ) => {rotateY .value -=event .changeX / 300;});constclip =usePathValue ((path ) => {"worklet";path .transform (processTransform3d ([{translate : [50, 50] },{perspective : 300 },{rotateY :rotateY .value },{translate : [-50, -50] },]));},rrct );return (<GestureDetector gesture ={gesture }><Canvas style ={{flex : 1 }}><Path path ={clip } /></Canvas ></GestureDetector >);};
tsx
import {useSharedValue ,withSpring } from "react-native-reanimated";import {Gesture ,GestureDetector } from "react-native-gesture-handler";import {usePathValue ,Canvas ,Path ,processTransform3d ,Skia } from "@shopify/react-native-skia";constrrct =Skia .Path .Make ();rrct .addRRect (Skia .RRectXY (Skia .XYWHRect (0, 0, 100, 100), 10, 10));export constFrostedCard = () => {constrotateY =useSharedValue (0);constgesture =Gesture .Pan ().onChange ((event ) => {rotateY .value -=event .changeX / 300;});constclip =usePathValue ((path ) => {"worklet";path .transform (processTransform3d ([{translate : [50, 50] },{perspective : 300 },{rotateY :rotateY .value },{translate : [-50, -50] },]));},rrct );return (<GestureDetector gesture ={gesture }><Canvas style ={{flex : 1 }}><Path path ={clip } /></Canvas ></GestureDetector >);};
useClock
此 hook 返回一个数字,指示自 hook 激活以来经过的毫秒数。
tsx
import {Canvas ,useClock ,vec ,Circle } from "@shopify/react-native-skia";import {useDerivedValue } from "react-native-reanimated";export default functionApp () {constt =useClock ();consttransform =useDerivedValue (() => {constscale = (2 / (3 -Math .cos (2 *t .value ))) * 200;return [{translateX :scale *Math .cos (t .value ) },{translateY :scale * (Math .sin (2 *t .value ) / 2) },];});return (<Canvas style ={{flex : 1 }}><Circle c ={vec (0, 0)}r ={50}color ="cyan"transform ={transform } /></Canvas >);}
tsx
import {Canvas ,useClock ,vec ,Circle } from "@shopify/react-native-skia";import {useDerivedValue } from "react-native-reanimated";export default functionApp () {constt =useClock ();consttransform =useDerivedValue (() => {constscale = (2 / (3 -Math .cos (2 *t .value ))) * 200;return [{translateX :scale *Math .cos (t .value ) },{translateY :scale * (Math .sin (2 *t .value ) / 2) },];});return (<Canvas style ={{flex : 1 }}><Circle c ={vec (0, 0)}r ={50}color ="cyan"transform ={transform } /></Canvas >);}
画布大小
Canvas 元素具有一个 onSize
属性,该属性可以接收一个共享值,每当画布大小更改时,该共享值都会更新。
tsx
import {useSharedValue } from "react-native-reanimated";import {Fill ,Canvas } from "@shopify/react-native-skia";constDemo = () => {// size will be updated as the canvas size changesconstsize =useSharedValue ({width : 0,height : 0 });return (<Canvas style ={{flex : 1 }}onSize ={size }><Fill color ="white" /></Canvas >);};
tsx
import {useSharedValue } from "react-native-reanimated";import {Fill ,Canvas } from "@shopify/react-native-skia";constDemo = () => {// size will be updated as the canvas size changesconstsize =useSharedValue ({width : 0,height : 0 });return (<Canvas style ={{flex : 1 }}onSize ={size }><Fill color ="white" /></Canvas >);};
useRectBuffer
创建一个用于动画的矩形数组。可被任何使用矩形数组作为属性的组件使用,例如 Atlas API。
tsx
import {useRectBuffer } from "@shopify/react-native-skia";constwidth = 256;constsize = 10;constrects = 100;// Important to not forget the worklet directiveconstrectBuffer =useRectBuffer (rects , (rect ,i ) => {"worklet";rect .setXYWH ((i *size ) %width ,Math .floor (i / (width /size )) *size ,size ,size );});
tsx
import {useRectBuffer } from "@shopify/react-native-skia";constwidth = 256;constsize = 10;constrects = 100;// Important to not forget the worklet directiveconstrectBuffer =useRectBuffer (rects , (rect ,i ) => {"worklet";rect .setXYWH ((i *size ) %width ,Math .floor (i / (width /size )) *size ,size ,size );});
useRSXformBuffer
创建一个用于动画的旋转缩放变换数组。可被任何使用旋转缩放变换数组作为属性的组件使用,例如 Atlas API。
tsx
import {useRSXformBuffer } from "@shopify/react-native-skia";import {useSharedValue } from "react-native-reanimated";constxforms = 100;constpos =useSharedValue ({x : 0,y : 0 });// Important to not forget the worklet directiveconsttransforms =useRSXformBuffer (xforms , (val ,i ) => {"worklet";constr =Math .atan2 (pos .value .y ,pos .value .x );val .set (Math .cos (r ),Math .sin (r ), 0, 0);});
tsx
import {useRSXformBuffer } from "@shopify/react-native-skia";import {useSharedValue } from "react-native-reanimated";constxforms = 100;constpos =useSharedValue ({x : 0,y : 0 });// Important to not forget the worklet directiveconsttransforms =useRSXformBuffer (xforms , (val ,i ) => {"worklet";constr =Math .atan2 (pos .value .y ,pos .value .x );val .set (Math .cos (r ),Math .sin (r ), 0, 0);});