手势
当与 reanimated 集成时,我们建议使用 react-native-gesture-handler。
我们准备了一些教程,展示了在 Skia 绘图中使用高级手势。
tsx
import {useWindowDimensions } from "react-native";import {Canvas ,Circle ,Fill } from "@shopify/react-native-skia";import {GestureDetector ,Gesture } from "react-native-gesture-handler";import {useSharedValue ,withDecay } from "react-native-reanimated";export constAnimationWithTouchHandler = () => {const {width } =useWindowDimensions ();constleftBoundary = 0;constrightBoundary =width ;consttranslateX =useSharedValue (width / 2);constgesture =Gesture .Pan ().onChange ((e ) => {translateX .value +=e .changeX ;}).onEnd ((e ) => {translateX .value =withDecay ({velocity :e .velocityX ,clamp : [leftBoundary ,rightBoundary ],});});return (<GestureDetector gesture ={gesture }><Canvas style ={{flex : 1 }}><Fill color ="white" /><Circle cx ={translateX }cy ={40}r ={20}color ="#3E3E" /></Canvas ></GestureDetector >);};
tsx
import {useWindowDimensions } from "react-native";import {Canvas ,Circle ,Fill } from "@shopify/react-native-skia";import {GestureDetector ,Gesture } from "react-native-gesture-handler";import {useSharedValue ,withDecay } from "react-native-reanimated";export constAnimationWithTouchHandler = () => {const {width } =useWindowDimensions ();constleftBoundary = 0;constrightBoundary =width ;consttranslateX =useSharedValue (width / 2);constgesture =Gesture .Pan ().onChange ((e ) => {translateX .value +=e .changeX ;}).onEnd ((e ) => {translateX .value =withDecay ({velocity :e .velocityX ,clamp : [leftBoundary ,rightBoundary ],});});return (<GestureDetector gesture ={gesture }><Canvas style ={{flex : 1 }}><Fill color ="white" /><Circle cx ={translateX }cy ={40}r ={20}color ="#3E3E" /></Canvas ></GestureDetector >);};
元素跟踪
一个常见的用例是仅对画布上的特定元素激活手势。手势处理器在这方面表现出色,因为它可以考虑应用于元素的所有变换,例如平移、缩放和旋转。为了跟踪每个元素,在其上覆盖一个动画视图,确保应用于画布元素的相同变换也镜像到动画视图上。
在下面的示例中,每个圆都由两个手势处理器分别跟踪。
tsx
import {View } from "react-native";import {Canvas ,Circle ,Fill } from "@shopify/react-native-skia";import {GestureDetector ,Gesture } from "react-native-gesture-handler";importAnimated , {useSharedValue ,useAnimatedStyle } from "react-native-reanimated";constradius = 30;export constElementTracking = () => {// The position of the ballconstx =useSharedValue (100);consty =useSharedValue (100);// This style will be applied to the "invisible" animated view// that overlays the ballconststyle =useAnimatedStyle (() => ({position : "absolute",top : -radius ,left : -radius ,width :radius * 2,height :radius * 2,transform : [{translateX :x .value }, {translateY :y .value }],}));// The gesture handler for the ballconstgesture =Gesture .Pan ().onChange ((e ) => {x .value +=e .x ;y .value +=e .y ;});return (<View style ={{flex : 1 }}><Canvas style ={{flex : 1 }}><Fill color ="white" /><Circle cx ={x }cy ={y }r ={radius }color ="cyan" /></Canvas ><GestureDetector gesture ={gesture }><Animated .View style ={style } /></GestureDetector ></View >);};
tsx
import {View } from "react-native";import {Canvas ,Circle ,Fill } from "@shopify/react-native-skia";import {GestureDetector ,Gesture } from "react-native-gesture-handler";importAnimated , {useSharedValue ,useAnimatedStyle } from "react-native-reanimated";constradius = 30;export constElementTracking = () => {// The position of the ballconstx =useSharedValue (100);consty =useSharedValue (100);// This style will be applied to the "invisible" animated view// that overlays the ballconststyle =useAnimatedStyle (() => ({position : "absolute",top : -radius ,left : -radius ,width :radius * 2,height :radius * 2,transform : [{translateX :x .value }, {translateY :y .value }],}));// The gesture handler for the ballconstgesture =Gesture .Pan ().onChange ((e ) => {x .value +=e .x ;y .value +=e .y ;});return (<View style ={{flex : 1 }}><Canvas style ={{flex : 1 }}><Fill color ="white" /><Circle cx ={x }cy ={y }r ={radius }color ="cyan" /></Canvas ><GestureDetector gesture ={gesture }><Animated .View style ={style } /></GestureDetector ></View >);};