Skip to content

Commit 44273d7

Browse files
committed
velocity test
1 parent 2d8d8f0 commit 44273d7

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

apps/common-app/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import LogicDetectorExample from './src/v3_api/svg/svg';
8787
import V3Hover from './src/v3_api/hover/index';
8888
import V3Overlap from './src/v3_api/overlap/index';
8989
import V3Calculator from './src/v3_api/calculator/index';
90+
import V3Velocity from './src/v3_api/velocity_test/index';
9091

9192
import { Icon } from '@swmansion/icons';
9293

@@ -114,6 +115,7 @@ const EXAMPLES: ExamplesSection[] = [
114115
{ name: 'V3 Hover', component: V3Hover },
115116
{ name: 'V3 Overlap', component: V3Overlap },
116117
{ name: 'V3 Calculator', component: V3Calculator },
118+
{ name: 'V3 Velocity Test', component: V3Velocity },
117119
],
118120
},
119121
{
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { StyleSheet, View } from 'react-native';
2+
import Animated, {
3+
interpolateColor,
4+
measure,
5+
useAnimatedRef,
6+
useAnimatedStyle,
7+
useSharedValue,
8+
withDecay,
9+
withTiming,
10+
} from 'react-native-reanimated';
11+
12+
import React from 'react';
13+
import { NativeDetector, usePan } from 'react-native-gesture-handler';
14+
15+
const BOX_SIZE = 120;
16+
17+
export default function App() {
18+
const aref = useAnimatedRef<View>();
19+
const offsetX = useSharedValue(0);
20+
const offsetY = useSharedValue(0);
21+
const isPressed = useSharedValue(false);
22+
const colorProgress = useSharedValue(0);
23+
24+
const pan = usePan({
25+
onBegin: () => {
26+
'worklet';
27+
isPressed.value = true;
28+
colorProgress.value = withTiming(1, {
29+
duration: 100,
30+
});
31+
},
32+
onUpdate: (event) => {
33+
'worklet';
34+
offsetX.value += event.handlerData.changeX;
35+
offsetY.value += event.handlerData.changeY;
36+
},
37+
onFinalize: (event) => {
38+
'worklet';
39+
isPressed.value = false;
40+
colorProgress.value = withTiming(0, {
41+
duration: 100,
42+
});
43+
// If we can't get view size, just ignore it. Half of the view will be
44+
// able to go outside the screen
45+
const size = measure(aref) ?? { width: 0, height: 0 };
46+
47+
offsetX.value = withDecay({
48+
velocity: event.handlerData.velocityX,
49+
clamp: [-size.width / 2 + BOX_SIZE / 2, size.width / 2 - BOX_SIZE / 2],
50+
rubberBandEffect: true,
51+
rubberBandFactor: 0.75,
52+
});
53+
54+
offsetY.value = withDecay({
55+
velocity: event.handlerData.velocityY,
56+
clamp: [
57+
-size.height / 2 + BOX_SIZE / 2,
58+
size.height / 2 - BOX_SIZE / 2,
59+
],
60+
rubberBandEffect: true,
61+
rubberBandFactor: 0.75,
62+
});
63+
},
64+
});
65+
66+
const animatedStyles = useAnimatedStyle(() => {
67+
const backgroundColor = interpolateColor(
68+
colorProgress.value,
69+
[0, 1],
70+
['#0a2688', '#6fcef5']
71+
);
72+
73+
return {
74+
transform: [
75+
{ translateX: offsetX.value },
76+
{ translateY: offsetY.value },
77+
{ scale: withTiming(isPressed.value ? 1.2 : 1, { duration: 100 }) },
78+
],
79+
backgroundColor,
80+
};
81+
});
82+
83+
return (
84+
<View style={styles.container} ref={aref} collapsable={false}>
85+
<NativeDetector gesture={pan}>
86+
<Animated.View style={[styles.box, animatedStyles]} />
87+
</NativeDetector>
88+
</View>
89+
);
90+
}
91+
92+
const styles = StyleSheet.create({
93+
container: {
94+
flex: 1,
95+
alignItems: 'center',
96+
justifyContent: 'center',
97+
height: '100%',
98+
},
99+
box: {
100+
width: BOX_SIZE,
101+
height: BOX_SIZE,
102+
borderRadius: BOX_SIZE / 2,
103+
// @ts-expect-error `grab` is correct value for `cursor` property
104+
cursor: 'grab',
105+
},
106+
});

0 commit comments

Comments
 (0)