title: React-Native Animated lags behind in low end Android phones
body: <p>I am trying to implement an animation that is supposed to be run on iOS and Android devices.</p>
  
  <p>In iOS the performance seems satisfactory (tested with iPhone 6 Plus and up).</p>
  
  <p>On the other hand for some Android devices the animations lag behind.</p>
  
  <p>The question is, what kind of actions can be taken to avoid the performance problem (apart from the usage of <code>useNativeDriver={true}</code> directive, which is already in the code)?</p>
  
  <p>The code is like that:</p>
  
  <pre><code>import * as React from 'react';
  import {
    Animated,
    ImageBackground,
    StyleSheet,
    Image,
    Easing,
    TextInput,
    View,
    Text,
  } from 'react-native';
  import { PanGestureHandler, State } from 'react-native-gesture-handler';
  import backImg from './background.png';
  
  const c_initial_coordinate_left = 100;
  const c_initial_coordinate_top = 100;
  
  export default class App extends React.Component {
    constructor(props) {
      super(props);
      this.state = {};
      this.spaceAnimatedTranslations = new Animated.ValueXY();
      this.spaceAnimatedTranslations2 = new Animated.ValueXY();
      this.spaceAnimatedTranslations3 = new Animated.ValueXY();
      this.spaceAnimatedTranslations4 = new Animated.ValueXY();
      this.spaceAnimatedTranslations5 = new Animated.ValueXY();
      this.spaceAnimatedTranslations.addListener(value =&gt; (this.spaceAnimatedTranslations_value = value));
      this.spaceAnimatedTranslations2.addListener(value =&gt; (this.spaceAnimatedTranslations_value2 = value));
      this.spaceAnimatedTranslations3.addListener(value =&gt; (this.spaceAnimatedTranslations_value3 = value));
      this.spaceAnimatedTranslations4.addListener(value =&gt; (this.spaceAnimatedTranslations_value4 = value));
      this.spaceAnimatedTranslations5.addListener(value =&gt; (this.spaceAnimatedTranslations_value5 = value));
      this._animatedStyle = {transform: [{ translateX: this.spaceAnimatedTranslations.x }, { translateY: this.spaceAnimatedTranslations.y },],};
      this._animatedStyle2 = {transform: [{ translateX: this.spaceAnimatedTranslations2.x }, { translateY: this.spaceAnimatedTranslations2.y },],};
      this._animatedStyle3 = {transform: [{ translateX: this.spaceAnimatedTranslations3.x }, { translateY: this.spaceAnimatedTranslations3.y },],};
      this._animatedStyle4 = {transform: [{ translateX: this.spaceAnimatedTranslations4.x }, { translateY: this.spaceAnimatedTranslations4.y },],};
      this._animatedStyle5 = {transform: [{ translateX: this.spaceAnimatedTranslations5.x }, { translateY: this.spaceAnimatedTranslations5.y },],};
    }
  
    onSpaceMove(event) {
      let l_panTranslateX = event.nativeEvent.translationX;
      let l_panTranslateY = event.nativeEvent.translationY;
      let l_panStartX = event.nativeEvent.x - event.nativeEvent.translationX;
      let l_panStartY = event.nativeEvent.y - event.nativeEvent.translationY;
  
      let l_animationsArray = new Array();
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations2.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations3.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations4.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations5.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations2.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations3.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations4.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
      l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations5.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
      Animated.parallel(l_animationsArray).start();
  
      this.debug_message = `\n
        event.nativeEvent.translationX: ${Math.floor(
          event.nativeEvent.translationX
        )}
        event.nativeEvent.translationY: ${Math.floor(
          event.nativeEvent.translationY
        )}
        event.nativeEvent.absoluteX: ${Math.floor(event.nativeEvent.absoluteX)}
        event.nativeEvent.absoluteY: ${Math.floor(event.nativeEvent.absoluteY)}
        event.nativeEvent.x: ${Math.floor(event.nativeEvent.x)}
        event.nativeEvent.y: ${Math.floor(event.nativeEvent.y)}
        this.spaceAnimatedTranslations_value.x: ${Math.floor(
          this.spaceAnimatedTranslations_value.x
        )}
        this.spaceAnimatedTranslations_value.y: ${Math.floor(
          this.spaceAnimatedTranslations_value.y
        )}
        this.gestureStartedX: ${Math.floor(this.gestureStartedX)}
        this.gestureStartedY: ${Math.floor(this.gestureStartedY)}
          `;
      this.forceUpdate();
    }
  
    onSpaceMoveCompleted(event) {
      if (event.nativeEvent.state === State.BEGAN) {
        this.spaceAnimatedTranslations.flattenOffset();
        this.spaceAnimatedTranslations2.flattenOffset();
        this.spaceAnimatedTranslations3.flattenOffset();
        this.spaceAnimatedTranslations4.flattenOffset();
        this.spaceAnimatedTranslations5.flattenOffset();
        this.spaceAnimatedTranslations.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
        this.spaceAnimatedTranslations2.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
        this.spaceAnimatedTranslations3.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
        this.spaceAnimatedTranslations4.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
        this.spaceAnimatedTranslations5.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top ),});
        this.gestureStartedX = event.nativeEvent.absoluteX;
        this.gestureStartedY = event.nativeEvent.absoluteY;
      }
      if (event.nativeEvent.state === State.END) {
        this.onSpaceMove(event);
      }
    }
  
    render() {
      return (
        &lt;ImageBackground source={backImg} style={{ flex: 1 }}&gt;
          {this.debug_message ? (
            &lt;Text style={{ color: 'white' }}&gt;{this.debug_message}&lt;/Text&gt;
          ) : (
            undefined
          )}
  
          &lt;PanGestureHandler
            key={`test`}
            onGestureEvent={e =&gt; this.onSpaceMove(e)}
            onHandlerStateChange={e =&gt; this.onSpaceMoveCompleted(e)}&gt;
            &lt;Animated.View
              ref={ref =&gt; {
                this.testAnimatedView = ref;
              }}
              style={[styles._animatable_view, this._animatedStyle]}
              useNativeDriver={true}&gt;
              &lt;View style={styles._box_content}&gt;
                &lt;Text
                  style={{
                    width: '100%',
                    height: '100%',
                    fontSize: 15,
                    textAlign: 'center',
                    textAlignVertical: 'center',
                    borderRadius: 20,
                  }}
                  editable={false}
                  ref={ref =&gt; {
                    this.textInputRef = ref;
                  }}
                &gt;
                {'Master (1) (DRAG THIS ONE)'}
                &lt;/Text&gt;
              &lt;/View&gt;
            &lt;/Animated.View&gt;
          &lt;/PanGestureHandler&gt;
            &lt;Animated.View
              ref={ref =&gt; {
                this.testAnimatedView2 = ref;
              }}
              style={[styles._animatable_view2, this._animatedStyle2]}
              useNativeDriver={true}&gt;
              &lt;View style={styles._box_content}&gt;
                &lt;Text
                  style={{
                    width: '100%',
                    height: '100%',
                    fontSize: 15,
                    textAlign: 'center',
                    textAlignVertical: 'center',
                    borderRadius: 20,
                  }}
                  editable={false}
                  ref={ref =&gt; {
                    this.textInputRef = ref;
                  }}
                &gt;
                {'Slave (2) '}
                &lt;/Text&gt;
              &lt;/View&gt;
            &lt;/Animated.View&gt;
            &lt;Animated.View
              ref={ref =&gt; {
                this.testAnimatedView3 = ref;
              }}
              style={[styles._animatable_view3, this._animatedStyle3]}
              useNativeDriver={true}&gt;
              &lt;View style={styles._box_content}&gt;
                &lt;Text
                  style={{
                    width: '100%',
                    height: '100%',
                    fontSize: 15,
                    textAlign: 'center',
                    textAlignVertical: 'center',
                    borderRadius: 20,
                  }}
                  editable={false}
                  ref={ref =&gt; {
                    this.textInputRef = ref;
                  }}
                &gt;
                {'Slave (3) '}
                &lt;/Text&gt;
              &lt;/View&gt;
            &lt;/Animated.View&gt;
            &lt;Animated.View
              ref={ref =&gt; {
                this.testAnimatedView4 = ref;
              }}
              style={[styles._animatable_view4, this._animatedStyle4]}
              useNativeDriver={true}&gt;
              &lt;View style={styles._box_content}&gt;
                &lt;Text
                  style={{
                    width: '100%',
                    height: '100%',
                    fontSize: 15,
                    textAlign: 'center',
                    textAlignVertical: 'center',
                    borderRadius: 20,
                  }}
                  editable={false}
                  ref={ref =&gt; {
                    this.textInputRef = ref;
                  }}
                &gt;
                {'Slave (4) '}
                &lt;/Text&gt;
              &lt;/View&gt;
            &lt;/Animated.View&gt;
            &lt;Animated.View
              ref={ref =&gt; {
                this.testAnimatedView5 = ref;
              }}
              style={[styles._animatable_view5, this._animatedStyle5]}
              useNativeDriver={true}&gt;
              &lt;View style={styles._box_content}&gt;
                &lt;Text
                  style={{
                    width: '100%',
                    height: '100%',
                    fontSize: 15,
                    textAlign: 'center',
                    textAlignVertical: 'center',
                    borderRadius: 20,
                  }}
                  editable={false}
                  ref={ref =&gt; {
                    this.textInputRef = ref;
                  }}
                &gt;
                {'Slave (5) '}
                &lt;/Text&gt;
              &lt;/View&gt;
            &lt;/Animated.View&gt;
        &lt;/ImageBackground&gt;
      );
    }
  }
  
  const styles = StyleSheet.create({
    _animatable_view: {
      flex: 1,
      width: 250,
      height: 50,
      top: c_initial_coordinate_top,
      left: c_initial_coordinate_left,
      position: 'absolute',
      backgroundColor: '#ABC',
      alignItems: 'center',
      justifyContent: 'center',
      borderColor: 'gainsboro',
      borderWidth: 2,
    },
    _animatable_view2: {
      flex: 1,
      width: 250,
      height: 50,
      top: c_initial_coordinate_top + 100,
      left: c_initial_coordinate_left,
      position: 'absolute',
      backgroundColor: '#ABC',
      alignItems: 'center',
      justifyContent: 'center',
      borderColor: 'gainsboro',
      borderWidth: 2,
    },
    _animatable_view3: {
      flex: 1,
      width: 250,
      height: 50,
      top: c_initial_coordinate_top + 200,
      left: c_initial_coordinate_left,
      position: 'absolute',
      backgroundColor: '#ABC',
      alignItems: 'center',
      justifyContent: 'center',
      borderColor: 'gainsboro',
      borderWidth: 2,
    },
    _animatable_view4: {
      flex: 1,
      width: 250,
      height: 50,
      top: c_initial_coordinate_top + 300,
      left: c_initial_coordinate_left,
      position: 'absolute',
      backgroundColor: '#ABC',
      alignItems: 'center',
      justifyContent: 'center',
      borderColor: 'gainsboro',
      borderWidth: 2,
    },
    _animatable_view5: {
      flex: 1,
      width: 250,
      height: 50,
      top: c_initial_coordinate_top + 400,
      left: c_initial_coordinate_left,
      position: 'absolute',
      backgroundColor: '#ABC',
      alignItems: 'center',
      justifyContent: 'center',
      borderColor: 'gainsboro',
      borderWidth: 2,
    },
    _box_content: {
      flex: 1,
      height: '100%',
      width: '100%',
      borderRadius: Math.min(this.rectangleHeight, this.rectangleWidth) / 2,
      alignItems: 'center',
      justifyContent: 'center',
      borderColor: 'gainsboro',
      borderWidth: 2,
      opacity: 0.9,
    },
  });
  </code></pre>
  
  <p>This can be seen in action in this snack: <a href="https://snack.expo.io/@mehmetkaplan/movetextwithgesturesingle" rel="nofollow noreferrer">https://snack.expo.io/@mehmetkaplan/movetextwithgesturesingle</a></p>
  
  <p>Additionally, in order to feel the performance problem I generated another snack, which simply animates 5 objects simultaneously. If you run this through low end Android devices, you can feel the performance problem: <a href="https://snack.expo.io/@mehmetkaplan/movetextwithgesturemulti" rel="nofollow noreferrer">https://snack.expo.io/@mehmetkaplan/movetextwithgesturemulti</a></p>