Quantcast
Channel: Active questions tagged react-native+android - Stack Overflow
Viewing all articles
Browse latest Browse all 28460

React-Native Animated lags behind in low end Android phones

$
0
0

I am trying to implement an animation that is supposed to be run on iOS and Android devices.

In iOS the performance seems satisfactory (tested with iPhone 6 Plus and up).

On the other hand for some Android devices the animations lag behind.

The question is, what kind of actions can be taken to avoid the performance problem (apart from the usage of useNativeDriver={true} directive, which is already in the code)?

The code is like that:

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 => (this.spaceAnimatedTranslations_value = value));
    this.spaceAnimatedTranslations2.addListener(value => (this.spaceAnimatedTranslations_value2 = value));
    this.spaceAnimatedTranslations3.addListener(value => (this.spaceAnimatedTranslations_value3 = value));
    this.spaceAnimatedTranslations4.addListener(value => (this.spaceAnimatedTranslations_value4 = value));
    this.spaceAnimatedTranslations5.addListener(value => (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 (
      <ImageBackground source={backImg} style={{ flex: 1 }}>
        {this.debug_message ? (
          <Text style={{ color: 'white' }}>{this.debug_message}</Text>
        ) : (
          undefined
        )}

        <PanGestureHandler
          key={`test`}
          onGestureEvent={e => this.onSpaceMove(e)}
          onHandlerStateChange={e => this.onSpaceMoveCompleted(e)}>
          <Animated.View
            ref={ref => {
              this.testAnimatedView = ref;
            }}
            style={[styles._animatable_view, this._animatedStyle]}
            useNativeDriver={true}>
            <View style={styles._box_content}>
              <Text
                style={{
                  width: '100%',
                  height: '100%',
                  fontSize: 15,
                  textAlign: 'center',
                  textAlignVertical: 'center',
                  borderRadius: 20,
                }}
                editable={false}
                ref={ref => {
                  this.textInputRef = ref;
                }}
              >
              {'Master (1) (DRAG THIS ONE)'}
              </Text>
            </View>
          </Animated.View>
        </PanGestureHandler>
          <Animated.View
            ref={ref => {
              this.testAnimatedView2 = ref;
            }}
            style={[styles._animatable_view2, this._animatedStyle2]}
            useNativeDriver={true}>
            <View style={styles._box_content}>
              <Text
                style={{
                  width: '100%',
                  height: '100%',
                  fontSize: 15,
                  textAlign: 'center',
                  textAlignVertical: 'center',
                  borderRadius: 20,
                }}
                editable={false}
                ref={ref => {
                  this.textInputRef = ref;
                }}
              >
              {'Slave (2) '}
              </Text>
            </View>
          </Animated.View>
          <Animated.View
            ref={ref => {
              this.testAnimatedView3 = ref;
            }}
            style={[styles._animatable_view3, this._animatedStyle3]}
            useNativeDriver={true}>
            <View style={styles._box_content}>
              <Text
                style={{
                  width: '100%',
                  height: '100%',
                  fontSize: 15,
                  textAlign: 'center',
                  textAlignVertical: 'center',
                  borderRadius: 20,
                }}
                editable={false}
                ref={ref => {
                  this.textInputRef = ref;
                }}
              >
              {'Slave (3) '}
              </Text>
            </View>
          </Animated.View>
          <Animated.View
            ref={ref => {
              this.testAnimatedView4 = ref;
            }}
            style={[styles._animatable_view4, this._animatedStyle4]}
            useNativeDriver={true}>
            <View style={styles._box_content}>
              <Text
                style={{
                  width: '100%',
                  height: '100%',
                  fontSize: 15,
                  textAlign: 'center',
                  textAlignVertical: 'center',
                  borderRadius: 20,
                }}
                editable={false}
                ref={ref => {
                  this.textInputRef = ref;
                }}
              >
              {'Slave (4) '}
              </Text>
            </View>
          </Animated.View>
          <Animated.View
            ref={ref => {
              this.testAnimatedView5 = ref;
            }}
            style={[styles._animatable_view5, this._animatedStyle5]}
            useNativeDriver={true}>
            <View style={styles._box_content}>
              <Text
                style={{
                  width: '100%',
                  height: '100%',
                  fontSize: 15,
                  textAlign: 'center',
                  textAlignVertical: 'center',
                  borderRadius: 20,
                }}
                editable={false}
                ref={ref => {
                  this.textInputRef = ref;
                }}
              >
              {'Slave (5) '}
              </Text>
            </View>
          </Animated.View>
      </ImageBackground>
    );
  }
}

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

This can be seen in action in this snack: https://snack.expo.io/@mehmetkaplan/movetextwithgesturesingle

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: https://snack.expo.io/@mehmetkaplan/movetextwithgesturemulti


Viewing all articles
Browse latest Browse all 28460

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>