-
Notifications
You must be signed in to change notification settings - Fork 483
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0121d4f
commit 548f598
Showing
66 changed files
with
1,044 additions
and
1,693 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,90 @@ | ||
--- | ||
id: touch-events | ||
title: Touch Events | ||
sidebar_label: Touch Events | ||
slug: /animations/touch-events | ||
id: gestures | ||
title: Gestures | ||
sidebar_label: Gestures | ||
slug: /animations/gestures | ||
--- | ||
|
||
When integrating with [reanimated](/docs/animations/animations), we recommend using [react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/docs/). | ||
|
||
:::info | ||
We've prepared a few [tutorials](docs/tutorials#gestures) that showcase the use of advanced gestures within the context of Skia drawings. | ||
|
||
Currently, built-in Skia animations are dependant on the JS thread. | ||
For UI-thread animations with Reanimated 3, see [Reanimated support](/docs/animations/reanimated). | ||
```tsx twoslash | ||
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 const AnimationWithTouchHandler = () => { | ||
const { width } = useWindowDimensions(); | ||
const leftBoundary = 0; | ||
const rightBoundary = width; | ||
const translateX = useSharedValue(width / 2); | ||
|
||
::: | ||
const gesture = Gesture.Pan() | ||
.onChange((e) => { | ||
translateX.value += e.changeX; | ||
}) | ||
.onEnd((e) => { | ||
translateX.value = withDecay({ | ||
velocity: e.velocityX, | ||
clamp: [leftBoundary, rightBoundary], | ||
}); | ||
}); | ||
|
||
### useTouchHandler | ||
return ( | ||
<GestureDetector gesture={gesture}> | ||
<Canvas style={{ flex: 1 }}> | ||
<Fill color="white" /> | ||
<Circle cx={translateX} cy={40} r={20} color="#3E3E" /> | ||
</Canvas> | ||
</GestureDetector> | ||
); | ||
}; | ||
``` | ||
|
||
The `useTouchHandler` hook handles touches in the `Canvas`. | ||
It is meant to be used with values to animate canvas elements. | ||
## 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. | ||
|
||
The useTouchHandler hook provides you with callbacks for single touch events. | ||
To track multiple touches use the `useMultiTouchHandler` hook instead - it has | ||
the same API as the single touch hook. | ||
In the example below, each circle is tracked separately by two gesture handlers. | ||
|
||
```tsx twoslash | ||
import { | ||
Canvas, | ||
Circle, | ||
useTouchHandler, | ||
useValue, | ||
} from "@shopify/react-native-skia"; | ||
|
||
const MyComponent = () => { | ||
const cx = useValue(100); | ||
const cy = useValue(100); | ||
|
||
const touchHandler = useTouchHandler({ | ||
onActive: ({ x, y }) => { | ||
cx.current = x; | ||
cy.current = y; | ||
}, | ||
}); | ||
import { View } from "react-native"; | ||
import { Canvas, Circle, Fill } from "@shopify/react-native-skia"; | ||
import { GestureDetector, Gesture } from "react-native-gesture-handler"; | ||
import Animated, { useSharedValue, useAnimatedStyle } from "react-native-reanimated"; | ||
|
||
const radius = 30; | ||
|
||
export const ElementTracking = () => { | ||
// The position of the ball | ||
const x = useSharedValue(100); | ||
const y = useSharedValue(100); | ||
// This style will be applied to the "invisible" animated view | ||
// that overlays the ball | ||
const style = 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 ball | ||
const gesture = Gesture.Pan().onChange((e) => { | ||
x.value += e.x; | ||
y.value += e.y; | ||
}); | ||
return ( | ||
<Canvas style={{ flex: 1 }} onTouch={touchHandler}> | ||
<Circle cx={cx} cy={cy} r={10} color="red" /> | ||
</Canvas> | ||
<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> | ||
); | ||
}; | ||
``` | ||
``` |
Oops, something went wrong.