import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
// setInterval(() => {
// let iters = 1e8,
// sum = 0;
// while (iters-- > 0) sum += iters;
// }, 300);
const {
set,
cond,
eq,
add,
multiply,
lessThan,
spring,
startClock,
stopClock,
clockRunning,
sub,
defined,
Value,
Clock,
event,
} = Animated;
function runSpring(clock, value, velocity, dest) {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
time: new Value(0),
};
const config = {
damping: 7,
mass: 1,
stiffness: 121.6,
overshootClamping: false,
restSpeedThreshold: 0.001,
restDisplacementThreshold: 0.001,
toValue: new Value(0),
};
return [
cond(clockRunning(clock), 0, [
set(state.finished, 0),
set(state.velocity, velocity),
set(state.position, value),
set(config.toValue, dest),
startClock(clock),
]),
spring(clock, state, config),
cond(state.finished, stopClock(clock)),
state.position,
];
}
class Snappable extends Component {
constructor(props) {
super(props);
const TOSS_SEC = 0.2;
const dragX = new Value(0);
const state = new Value(-1);
const dragVX = new Value(0);
this._onGestureEvent = event([
{ nativeEvent: { translationX: dragX, velocityX: dragVX, state: state } },
]);
const transX = new Value();
const prevDragX = new Value(0);
const clock = new Clock();
// If transX has not yet been defined we stay in the center (value is 0).
// When transX is defined, it means drag has already occured. In such a case
// we want to snap to -100 if the final position of the block is below 0
// and to 100 otherwise.
// We also take into account gesture velocity at the moment of release. To
// do that we calculate final position of the block as if it was moving for
// TOSS_SEC seconds with a constant speed the block had when released (dragVX).
// So the formula for the final position is:
// finalX = transX + TOSS_SEC * dragVelocityX
//
const snapPoint = cond(
lessThan(add(transX, multiply(TOSS_SEC, dragVX)), 0),
-100,
100
);
this._transX = cond(
eq(state, State.ACTIVE),
[
stopClock(clock),
set(transX, add(transX, sub(dragX, prevDragX))),
set(prevDragX, dragX),
transX,
],
[
set(prevDragX, 0),
set(
transX,
cond(defined(transX), runSpring(clock, transX, dragVX, snapPoint), 0)
),
]
);
}
render() {
const { children, ...rest } = this.props;
return (
{children}
);
}
}
export default class Example extends Component {
static navigationOptions = {
title: 'Snappable Example',
};
render() {
return (
);
}
}
const BOX_SIZE = 100;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
box: {
width: BOX_SIZE,
height: BOX_SIZE,
borderColor: '#F5FCFF',
alignSelf: 'center',
backgroundColor: 'plum',
margin: BOX_SIZE / 2,
},
});