Gestures
When integrating with reanimated, we recommend using react-native-gesture-handler.
We've prepared a few tutorials that showcase the use of advanced gestures within the context of Skia drawings.
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 >);};
Element Tracking
A common use-case involves activating gestures only for a specific element on the Canvas. The Gesture Handler excels in this area as it can account for all the transformations applied to an element, such as translations, scaling, and rotations. To track each element, overlay an animated view on it, ensuring that the same transformations applied to the canvas element are mirrored on the animated view.
In the example below, each circle is tracked separately by two gesture handlers.
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 >);};