First of all, congratulations for this library. I am super excited about the value this will bring to the community to achieve gestures/interactions at 60 FPS on the main thread, in a declarative and composable way. Keep it going! ๐ช
I've been tinkering with it during the last to days and I've come across an issue with the timing
node. I am using a simple animation when the component mounts to animate some navigation bar on the x-axis using transformX
. With timing
, what it happens is that the animation does not occur, the view just goes to the final value after the duration abruptly.
I am attaching the snippet I've used for that experiment. Maybe I am missing something on the timing
configuration, or you'd lean towards some implementation flaw?
import * as React from 'react';
import { View, StyleSheet, Text, Easing } from 'react-native';
import Animated from 'react-native-reanimated';
const {
Value,
cond,
set,
startClock,
clockRunning,
stopClock,
Clock,
timing,
spring,
} = Animated;
const NAV_BAR_HEIGHT = 56;
function runTiming(clock, value, dest) {
const state = {
finished: new Value(0),
position: new Value(0),
time: new Value(0),
frameTime: new Value(0),
};
const config = {
duration: 3000,
toValue: new Value(0),
easing: Easing.inOut(Easing.ease),
};
return [
cond(clockRunning(clock), 0, [
// If the clock isn't running we reset all the animation params and start the clock
set(state.finished, 0),
set(state.time, 0),
set(state.position, value),
set(state.frameTime, 0),
set(config.toValue, dest),
startClock(clock),
]),
// we run the step here that is going to update position
timing(clock, state, config),
// if the animation is over we stop the clock
cond(state.finished, stopClock(clock)),
// we made the block return the updated position
state.position,
];
}
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: 12,
mass: 1,
stiffness: 50,
overshootClamping: true,
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),
]),
// we run the step here that is going to update position
spring(clock, state, config),
// if the animation is over we stop the clock
cond(state.finished, stopClock(clock)),
// we made the block return the updated position
state.position,
];
}
class Example extends React.Component {
componentWillMount() {
this.transX = new Value(0);
// Clock
const clock = new Clock();
// Timing does not work, there is no animation, just an abrupt change to the end frame.
// this.transXAnimated = set(this.transX, runTiming(clock, 0, 300));
this.transXAnimated = set(
this.transX,
runSpring(clock, this.transX, 0, 300),
);
}
render() {
return (
<View style={styles.container}>
<Animated.View
style={[
styles.navBar,
{
transform: [
{
translateX: this.transXAnimated,
},
],
},
]}
>
<Text style={[styles.navBarTitle]}>
Navigation Bar
</Text>
</Animated.View>
</View>
);
}
}
export default Example;
const styles = StyleSheet.create({
container: {
flex: 1,
},
navBar: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#C2185B',
borderBottomColor: '#dedede',
borderBottomWidth: 1,
height: NAV_BAR_HEIGHT,
zIndex: 2,
},
navBarTitle: {
color: 'white',
fontSize: 20,
},
});