Gestures: Dragging and Spring Animation
Pairing Skia with react-native-gesture-handler is how you build draggable, physics-feeling graphics, a slider, a drag-to-dismiss card, or a springy button.
Reading a pan gesture into a Skia value
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import { Canvas, Circle, useValue } from '@shopify/react-native-skia';
export function DraggableDot() {
const cx = useValue(100);
const cy = useValue(100);
const pan = Gesture.Pan().onChange((e) => {
cx.current += e.changeX;
cy.current += e.changeY;
});
return (
<GestureDetector gesture={pan}>
<Canvas style={{ flex: 1 }}>
<Circle cx={cx} cy={cy} r={30} color="#22d3ee" />
</Canvas>
</GestureDetector>
);
}
onChange fires on every frame of the gesture with the delta since the last event (changeX/changeY), adding that delta straight to the Skia values moves the circle in perfect sync with the finger, again with zero React re-renders.
Springing back on release
runSpring animates a value using spring physics (mass, damping, stiffness) instead of a fixed duration, ideal for "let go and it snaps back":
import { runSpring } from '@shopify/react-native-skia';
const pan = Gesture.Pan()
.onChange((e) => {
cx.current += e.changeX;
cy.current += e.changeY;
})
.onEnd(() => {
runSpring(cx, 100, { mass: 1, damping: 10, stiffness: 150 });
runSpring(cy, 100, { mass: 1, damping: 10, stiffness: 150 });
});
Higher damping settles faster with less bounce, higher stiffness snaps back faster, tune both to taste.