Style property 'width' is not supported by native animated module: need advice for rewriting my code

27.6k views Asked by At

I inherited the following component which worked well with former versions of react-native, displaying an opaque scrolling progress bar on buttons displayed by other components.

Recently, when I upgraded to react-native 0.62.2 I got an error requesting to add useNativeDriver. When adding it and setting it to 'yes', I got an error saying that "style property 'width' is not supported by native animated module".

When setting useNativeDriver to false I don't get an error but the animation doesn't work (at least not on android. Didn't test on iOS).

Any suggestion on how to modify the code to make it work with the newest version of react-native?

import React, { Component } from 'react';
import { Animated, Easing } from 'react-native';
import { connect } from 'react-redux';

class ProgressBar_Module extends Component {
  constructor(props) {
    super(props);

    this.state = {
      progress: 0
    }
    this.d_isMounted = false;
    this.d_initialTime = 0;
    this.d_animation_width = new Animated.Value(1);
    this.d_animation_progressTime = 3000;
  }

  componentDidMount() {
    this.d_initialTime = Date.now();
    this.d_isMounted = true;
    this.progressCount();
  }

  componentDidUpdate(prevProps) {
    if(prevProps.timerStart < this.props.timerStart) {
      this.setState({
        animation_width: new Animated.Value(1),
        animation_progressTime: 3000
      });
      this.progressCount(true)
    }
  }

  componentWillUnmount() {
    this.d_isMounted = false;
  }

  progressCount = (reset) => {
    if( reset ) {
      this.d_animation_width = new Animated.Value(1);
      this.d_animation_progressTime = 3000;
    }
    Animated.timing(this.d_animation_width, {
      toValue: 175,
      duration: this.d_animation_progressTime,
      easing: Easing.linear
    }).start(() => {
      if(this.props.timer && this.d_animation_width.__getValue() === 175) {
        this.props.onPress();
      }
    })
  }

  render() {

    return (
      <Animated.View
        style={[
          {
            position: 'absolute',
            left: 0,
            height: '150%',
            width: 0,
            zIndex: 1,
            backgroundColor: 'black',
          },
          { width: this.props.timer !== false ?
              this.d_animation_width : 175 }
        ]}
        onPress={this.props.onPress}
      >
      </Animated.View>
    )
  }
}

const mapStateToProps = state => {
  return {
    timer: state.get('ui').get('timer').get('timer'),
    reset: state.get('ui').get('resetTimer').get('resetTimer'),
    timerStart: state.get('ui').get('resetTimer').get('timerStart')
  }
};

export const ProgressBar = connect(mapStateToProps)(ProgressBar_Module);
4

There are 4 answers

5
YaNuSH On BEST ANSWER

Instead of animating the width, try using transform and scaleX. Here is some reference to react native transforms: https://reactnative.dev/docs/transforms

0
Yossi On

Following @YaNuSH advice, I just needed to replace

   width: animatedValue

with:

transform: [{ scaleX: scaling }],

Full details:

Before:

Animated.timing(this.d_animation_width, {
      toValue: 175,
      duration: this.d_animation_progressTime,
      easing: Easing.linear
    }).start(()

After:

Animated.timing(this.d_animation_width, {
      toValue: 175,
      duration: this.d_animation_progressTime,
      easing: Easing.linear,
      useNativeDriver: true
    }).start(()

before:

return (
      <Animated.View
        style={[{
          position: 'absolute',
          left: 0,
          height: '150%',
          width: 0,
          zIndex: 1,
          backgroundColor: 'black',
        }, 
        {
          width: this.props.timer !== false ?
             this.d_animation_width : 175
        }]}
        onPress={this.props.onPress}
      >
      </Animated.View>
    )

after:

const scaling = this.props.timer !== false ? this.d_animation_width : 175;

return (
  <Animated.View
    style={[
      {
        position: 'absolute',
        left: 0,
        height: '150%',
        width: 2,
        zIndex: 1,
        backgroundColor: 'black',
      },
      {
        transform: [
          {
            scaleX: scaling
          },
        ],
      },
    ]}
    onPress={this.props.onPress}
  >
  </Animated.View>
)
2
Ranvijay Kumar Singh On

Try doing this.

useNativeDriver: false

It worked for me.

0
Mahendren Mahisha On
Animated.timing(this.loadingValue.width, {
        toValue: widthEnd,
        duration: 400,
        useNativeDriver: false //add this line into the library
      }).start();

      Animated.timing(this.loadingValue.borderRadius, {
        toValue: borderRadiusEnd,
        duration: 400,
        useNativeDriver: false //add this line into the library
      }).start();

      Animated.timing(this.loadingValue.opacity, {
        toValue: opacityEnd,
        duration: 300,
        useNativeDriver: false //add this line into the library
      }).start();

that's all... enjoy your coding...