question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Animation control, Clock reset

See original GitHub issue

Versions “react”: “16.6.1”, “react-native”: “0.57.5”, “react-native-reanimated”: “^1.0.0-alpha.10”,

I want to be able to run and stop animations, while being able to listen to touches. Basically it’s the progress indicator in audio player, so if audio is playing, animation is playing, if user drags the indicator, animation stops and I respond to gestures.

But I am lost with just simple running / stopping the animation. This is the current behavior, the box jumps by value like it would move if clock was running all the time. animationlag

I think it’s because of the Clock? Below are two different versions In the first one, I create one instance of clock and “control” that. In the second one, I create new instance of the clock every time the runTiming() function is called, still I can stop it without any reference by stopClock(new Clock()). How does this work? What am I missing? I so confused.

// @flow

import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import Animated, { Easing } from 'react-native-reanimated';
import React, { Component } from 'react';

const {
	Value,
	cond,
	clockRunning,
	startClock,
	set,
	timing,
	debug,
	stopClock,
	block,
	Clock,
	eq,
	call,
} = Animated;

function runTiming(clock, value, dest) {
// clock = new Clock();
	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.linear,
	};

	return block([
		cond(clockRunning(clock), 0, [
			set(state.finished, 0),
			set(state.time, 0),
			set(state.position, value),
			set(state.frameTime, 0),
			set(config.toValue, dest),
			startClock(clock),
		]),
		timing(clock, state, config),
		cond(state.finished, debug('stop clock', stopClock(clock))),
		set(value, state.position),
	]);
}

const PLAYER_STATE = {
	PAUSED: 0,
	PLAYING: 1,
};

class SimplePlayer extends Component<{}> {
	clock: Clock;
	trans: Value;
	playingState: Value;

	constructor() {
		super();
		this.clock = new Clock();
		this.trans = new Value(0);
		this.playingState = new Value(PLAYER_STATE.PAUSED);
	}

	render() {
		return (
			<View style={styles.container}>
				<Animated.Code>
					{() =>
						block([
							cond(eq(this.playingState, PLAYER_STATE.PLAYING), [
								runTiming(this.clock, this.trans, 360),
							]),
							cond(eq(this.playingState, PLAYER_STATE.PAUSED), [
								stopClock(this.clock),
							]),
							cond(eq(this.trans, 360), set(this.trans, 0)),
						])
					}
				</Animated.Code>
				<Animated.View
					style={[styles.box, { transform: [{ translateY: this.trans }] }]}
				/>
				<TouchableOpacity
					onPress={() => {
						this.playingState.setValue(PLAYER_STATE.PLAYING);
					}}
				>
					<Text>RUN ANIM</Text>
				</TouchableOpacity>
				<TouchableOpacity
					onPress={() => {
						this.playingState.setValue(PLAYER_STATE.PAUSED);
					}}
				>
					<Text>PAUSE ANIM</Text>
				</TouchableOpacity>
			</View>
		);
	}
}

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,
	},
});

second version (shortened) still works like the previous

function runTiming(value, dest) {
	const clock = new Clock(); // new clock instance
	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.linear,
	};

	return block([
		cond(clockRunning(clock), 0, [
			set(state.finished, 0),
			set(state.time, 0),
			set(state.position, value),
			set(state.frameTime, 0),
			set(config.toValue, dest),
			startClock(clock),
		]),
		timing(clock, state, config),
		cond(state.finished, debug('stop clock', stopClock(clock))),
		set(value, state.position),
	]);
}

const PLAYER_STATE = {
	PAUSED: 0,
	PLAYING: 1,
};

class SimplePlayer extends Component<{}> {
	trans: Value;
	playingState: Value;

	constructor() {
		super();
		// this.clock removed
		this.trans = new Value(0);
		this.playingState = new Value(PLAYER_STATE.PAUSED);
	}

	render() {
		return (
			<View style={styles.container}>
				<Animated.Code>
					{() =>
						block([
							cond(eq(this.playingState, PLAYER_STATE.PLAYING), [
								runTiming(this.trans, 360),
							]),
							cond(eq(this.playingState, PLAYER_STATE.PAUSED), [
								stopClock(new Clock()), // no reference to instance
							]),
							cond(eq(this.trans, 360), set(this.trans, 0)),
						])
					}
				</Animated.Code>
				<Animated.View
					style={[styles.box, { transform: [{ translateY: this.trans }] }]}
				/>
				<TouchableOpacity
					onPress={() => {
						this.playingState.setValue(PLAYER_STATE.PLAYING);
					}}
				>
					<Text>RUN ANIM</Text>
				</TouchableOpacity>
				<TouchableOpacity
					onPress={() => {
						this.playingState.setValue(PLAYER_STATE.PAUSED);
					}}
				>
					<Text>PAUSE ANIM</Text>
				</TouchableOpacity>
			</View>
		);
	}
}

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:6
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

5reactions
dalisalvadorcommented, Oct 7, 2019

Hi guys,

Thanks @CptFabulouso, I had a similar issue (I guess), and indeed the problem for me was that on pausing I had to store clock’s value on state.time.
Below a short example for those who might encounter the same issue (careful! shortened code…):

const runTiming = (clock, value, dest, time) => {
    const config = {
      duration: time,
      toValue: new Value(0),
      easing: Easing.inOut(Easing.ease),
    };

    const state = {
      paused: new Value(0),
      started: new Value(0),
      finished: new Value(0),
      position: new Value(0),
      time: new Value(0),
      frameTime: new Value(0),
    };

     return block([
      cond(
        clockRunning(clock),
        [
           cond(pauseFlag,  //See useEffect. 
            [  
                  set(state.paused, 1), 
                  set(state.time, clock),   //<== THIS SOLVED THE ISSUE
            [
                  set(state.paused, 0),  
                  set(config.toValue, dest)
            ]),
        ], [cond(not(state.started), [set(state.started, 1), startClock(clock)])],
       ),
       timing(clock, state, config),
       cond(state.finished, [stopClock(clock)]),
       state.position,
    ]);
  };



const pauseFlag = new Value(0);

//onChange prop.
  useEffect(() => {
    if (pause) pauseFlag.setValue(1);
    else pauseFlag.setValue(0);
  }, [pause]);


Cheers!

2reactions
kmagieracommented, Dec 19, 2019

Hey! I believe you have found the solution already.

I am not entirely sure but from reading through the code example you posted it appears like you expect the clock to restart from the time at which you have stopped it. This is not how the clocks have been designed in reanimated to behave. The way clocks work is that they always have the value of the current system time. So even when you stop them they will keep giving you the right time at the moment of evaluation. The only consequence of starting/stopping the clock is that when the clock is stopped it won’t trigger update for the dependant nodes (that is the pieces of your reanimated code which use the clock). However, that code may still be reevaluated because the evaluation has been triggered by an event.

In short the solution is that you want to operate on time deltas. One think you can do is store the time when you start the clock in some state value. Then, instead of using the timestamp returned from clock you use diff between that timestamp and start timestamp.

I’m going to close this issue as 1) we want to migrate away from hosting the discussions on github issues and solely use it for bug reports and 2) I believe it is now resolved. In case it still isn’t clean for you feel free to reopen the issue as, sadly, it is unlikely anyone will answer here when the issue is closed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

animation control by time/clock - Unity Answers
The best way to solve your problem is to use the javascript functions for getting the time and data (see here) when the...
Read more >
Set the start time and speed of an animation effect
On the Animations tab, in the Duration box, enter the number of seconds that you want the effect to run. Set the speed...
Read more >
How to Create a Separate Clock and control it with Custom ...
Why didn't the animation start? Note that the animation is performed with the clock of viewer in CesiumJS. In your code viewer 's...
Read more >
Instruction manual suspended animation clock? - Fixya
Setting the Timer: Press the 2 o'clock button to stop the timer. The hour/seconds counter sub-dial will show the elapsed hours and the...
Read more >
Support ClockClock 9
After each animation the clock hands align to show the time as a central ... the time is shown can be controlled and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found