Skip to content

Commit b9ba694

Browse files
DylanVannkmagiera
authored andcommitted
Add interpolate function from kmagiera with example. [WIP] (#11)
Interpolate function from #10 (comment) with extrapolation handling, examples, and documentation. Closes #10 .
1 parent 8d3ece3 commit b9ba694

File tree

13 files changed

+766
-23
lines changed

13 files changed

+766
-23
lines changed

Example/App.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React from 'react';
22
import { Text, View, FlatList, StyleSheet, YellowBox } from 'react-native';
3-
import { StackNavigator } from 'react-navigation';
3+
import { createStackNavigator } from 'react-navigation';
44
import { RectButton, ScrollView } from 'react-native-gesture-handler';
55

66
import Snappable from './snappable';
77
import ImageViewer from './imageViewer';
88
import Test from './test';
9+
import Interpolate from './src/interpolate';
910

1011
YellowBox.ignoreWarnings([
1112
'Warning: isMounted(...) is deprecated',
@@ -18,11 +19,12 @@ const SCREENS = {
1819
Snappable: { screen: Snappable, title: 'Snappable' },
1920
Test: { screen: Test, title: 'Test' },
2021
ImageViewer: { screen: ImageViewer, title: 'Image Viewer' },
22+
Interpolate: { screen: Interpolate, title: 'Interpolate' },
2123
};
2224

2325
class MainScreen extends React.Component {
2426
static navigationOptions = {
25-
title: '🎬 Reanimated Demo',
27+
title: '🎬 Reanimated Examples',
2628
};
2729
render() {
2830
const data = Object.keys(SCREENS).map(key => ({ key }));
@@ -57,7 +59,7 @@ class MainScreenItem extends React.Component {
5759
}
5860
}
5961

60-
const ExampleApp = StackNavigator(
62+
const ExampleApp = createStackNavigator(
6163
{
6264
Main: { screen: MainScreen },
6365
...SCREENS,

Example/imageViewer/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,9 @@ class Viewer extends Component {
420420
}
421421

422422
export default class Example extends Component {
423+
static navigationOptions = {
424+
title: 'Image Viewer Example',
425+
};
423426
render() {
424427
return (
425428
<View style={styles.container}>

Example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"react-native": "0.55.3",
1313
"react-native-gesture-handler": "^1.0.0",
1414
"react-native-reanimated": "file:../",
15-
"react-navigation": "^1.5.11"
15+
"react-navigation": "^2.0.4"
1616
},
1717
"devDependencies": {
1818
"babel-jest": "22.4.3",

Example/snappable/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class Snappable extends Component {
128128
}
129129

130130
export default class Example extends Component {
131+
static navigationOptions = {
132+
title: 'Snappable Example',
133+
};
131134
render() {
132135
return (
133136
<View style={styles.container}>

Example/src/Box.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import { StyleSheet } from 'react-native';
3+
import Animated, { Easing } from 'react-native-reanimated';
4+
5+
/**
6+
* Needs to be a class component for react-native-gesture-handler to put a ref on it.
7+
*/
8+
export default class Box extends React.Component {
9+
render() {
10+
const { style, ...props } = this.props;
11+
return <Animated.View style={[styles.box, style]} {...props} />;
12+
}
13+
}
14+
15+
const BOX_SIZE = 44;
16+
17+
const styles = StyleSheet.create({
18+
box: {
19+
width: BOX_SIZE,
20+
height: BOX_SIZE,
21+
alignSelf: 'center',
22+
backgroundColor: 'blue',
23+
margin: 10,
24+
},
25+
});

Example/src/Row.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
import { View, StyleSheet } from 'react-native';
3+
4+
const Row = ({ style, ...props }) => (
5+
<View style={[styles.style, style]} {...props} pointerEvents="box-none" />
6+
);
7+
8+
const styles = StyleSheet.create({
9+
style: {
10+
height: 64,
11+
},
12+
});
13+
14+
export default Row;
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
import React, { Component } from 'react';
2+
import { StyleSheet, View } from 'react-native';
3+
import Animated, { Easing } from 'react-native-reanimated';
4+
import { PanGestureHandler, State } from 'react-native-gesture-handler';
5+
import Box from '../Box';
6+
import Row from '../Row';
7+
8+
const {
9+
set,
10+
cond,
11+
sub,
12+
eq,
13+
and,
14+
add,
15+
call,
16+
multiply,
17+
lessThan,
18+
startClock,
19+
stopClock,
20+
clockRunning,
21+
block,
22+
timing,
23+
debug,
24+
spring,
25+
Value,
26+
Clock,
27+
event,
28+
interpolate,
29+
defined,
30+
} = Animated;
31+
32+
function runSpring(clock, value, velocity, dest) {
33+
const state = {
34+
finished: new Value(0),
35+
velocity: new Value(0),
36+
position: new Value(0),
37+
time: new Value(0),
38+
};
39+
40+
const config = {
41+
damping: 7,
42+
mass: 1,
43+
stiffness: 121.6,
44+
overshootClamping: false,
45+
restSpeedThreshold: 0.001,
46+
restDisplacementThreshold: 0.001,
47+
toValue: new Value(0),
48+
};
49+
50+
return [
51+
cond(clockRunning(clock), 0, [
52+
set(state.finished, 0),
53+
set(state.velocity, velocity),
54+
set(state.position, value),
55+
set(config.toValue, dest),
56+
startClock(clock),
57+
]),
58+
cond(state.finished, stopClock(clock)),
59+
state.position,
60+
];
61+
}
62+
63+
function runTiming(clock, value, dest) {
64+
const state = {
65+
finished: new Value(1),
66+
position: new Value(value),
67+
time: new Value(0),
68+
frameTime: new Value(0),
69+
};
70+
71+
const config = {
72+
duration: 500,
73+
toValue: new Value(0),
74+
easing: Easing.inOut(Easing.ease),
75+
};
76+
77+
const reset = [
78+
set(state.finished, 0),
79+
set(state.time, 0),
80+
set(state.frameTime, 0),
81+
];
82+
83+
return block([
84+
cond(and(state.finished, eq(state.position, value)), [
85+
...reset,
86+
set(config.toValue, dest),
87+
]),
88+
cond(and(state.finished, eq(state.position, dest)), [
89+
...reset,
90+
set(config.toValue, value),
91+
]),
92+
cond(clockRunning(clock), 0, startClock(clock)),
93+
timing(clock, state, config),
94+
state.position,
95+
]);
96+
}
97+
98+
const getAnimation = (min, max) => {
99+
const clock = new Clock();
100+
const state = {
101+
finished: new Value(1),
102+
position: new Value(min),
103+
time: new Value(0),
104+
frameTime: new Value(0),
105+
};
106+
107+
const config = {
108+
duration: 500,
109+
toValue: new Value(0),
110+
easing: Easing.inOut(Easing.ease),
111+
};
112+
113+
const reset = [
114+
set(state.finished, 0),
115+
set(state.time, 0),
116+
set(state.frameTime, 0),
117+
];
118+
119+
return block([
120+
cond(and(state.finished, eq(state.position, min)), [
121+
...reset,
122+
set(config.toValue, max),
123+
]),
124+
cond(and(state.finished, eq(state.position, max)), [
125+
...reset,
126+
set(config.toValue, min),
127+
]),
128+
cond(clockRunning(clock), 0, startClock(clock)),
129+
timing(clock, state, config),
130+
state.position,
131+
]);
132+
};
133+
134+
export default class AnimatedBounds extends Component {
135+
constructor(props) {
136+
super(props);
137+
const TOSS_SEC = 0.2;
138+
139+
const dragX = new Value(0);
140+
const state = new Value(-1);
141+
const dragVX = new Value(0);
142+
const transX = new Value();
143+
const prevDragX = new Value(0);
144+
const clock = new Clock();
145+
146+
this._onGestureEvent = event([
147+
{ nativeEvent: { translationX: dragX, velocityX: dragVX, state: state } },
148+
]);
149+
150+
const snapPoint = cond(
151+
lessThan(add(transX, multiply(TOSS_SEC, dragVX)), 0),
152+
-100,
153+
100
154+
);
155+
156+
this._transX = cond(
157+
eq(state, State.ACTIVE),
158+
[
159+
stopClock(clock),
160+
set(transX, add(transX, sub(dragX, prevDragX))),
161+
set(prevDragX, dragX),
162+
transX,
163+
],
164+
[
165+
set(prevDragX, 0),
166+
set(
167+
transX,
168+
cond(defined(transX), runSpring(clock, transX, dragVX, snapPoint), 0)
169+
),
170+
]
171+
);
172+
173+
this._transX = interpolate(this._transX, {
174+
inputRange: [-100, 100],
175+
outputRange: [-100, 100],
176+
extrapolate: 'clamp',
177+
});
178+
179+
const min = getAnimation(-100, -50);
180+
const max = getAnimation(100, 50);
181+
this._transXA = interpolate(this._transX, {
182+
inputRange: [-100, 100],
183+
outputRange: [min, max],
184+
extrapolate: 'clamp',
185+
});
186+
this.min = min;
187+
this.max = max;
188+
}
189+
render() {
190+
return (
191+
<View style={styles.container}>
192+
<Row>
193+
<Animated.View
194+
style={[styles.line, { transform: [{ translateX: -100 }] }]}
195+
/>
196+
<Animated.View
197+
style={[styles.line, { transform: [{ translateX: 100 }] }]}
198+
/>
199+
<PanGestureHandler
200+
maxPointers={1}
201+
onGestureEvent={this._onGestureEvent}
202+
onHandlerStateChange={this._onGestureEvent}>
203+
<Box style={{ transform: [{ translateX: this._transX }] }} />
204+
</PanGestureHandler>
205+
</Row>
206+
<Row>
207+
<Animated.View
208+
style={[styles.line, { transform: [{ translateX: this.min }] }]}
209+
/>
210+
<Animated.View
211+
style={[styles.line, { transform: [{ translateX: this.max }] }]}
212+
/>
213+
<Box style={{ transform: [{ translateX: this._transXA }] }} />
214+
</Row>
215+
</View>
216+
);
217+
}
218+
}
219+
220+
const styles = StyleSheet.create({
221+
container: {
222+
flex: 1,
223+
justifyContent: 'center',
224+
alignItems: 'center',
225+
},
226+
line: {
227+
position: 'absolute',
228+
alignSelf: 'center',
229+
backgroundColor: 'red',
230+
height: 64,
231+
width: 1,
232+
},
233+
});

0 commit comments

Comments
 (0)