wmsschlck
wmsschlck

Reputation: 85

How to animate the backgroundColor of a ScrollView in React Native

I want to animate the backgroundColor of a ScrollView, but always get a warning - and a non-animating ScrollView. Am I hitting a bug? Or is it simply not supported on a ScrollView? (It does work on a regular View.) I'm testing using Expo on an iOS iPhone.

Relevant code snippets:

<Animated.ScrollView
  contentContainerStyle={[
    styles.container,
    this.getCurrentColorOfBackground()
  ]}>
  <Text onPress={this.onPress} style={styles.question}>
    {this.state.question}
  </Text>
</Animated.ScrollView>

the getCurrentColorOfBackground() method:

  getCurrentColorOfBackground = () => ({
    backgroundColor: this.backgroundColor.interpolate({
      inputRange: [0, 100],
      outputRange: ["#00aaFF", "#808080"]
    })
  });

the animation itself:

this.backgroundColor = new Animated.Value(0);
Animated.timing(this.backgroundColor, {
  toValue: 100,
  duration: 1000 * 60
}).start();

The warning message:

20:17:58: Warning: Failed prop type: Invalid prop backgroundColor supplied to ScrollView: [object Object] Valid color formats are - '#f0f' (#rgb) - '#f0fc' (#rgba) - '#ff00ff' (#rrggbb) - '#ff00ff00' (#rrggbbaa) - 'rgb(255, 255, 255)' - 'rgba(255, 255, 255, 1.0)' - 'hsl(360, 100%, 100%)' - 'hsla(360, 100%, 100%, 1.0)' - 'transparent' - 'red' - 0xff00ff00 (0xrrggbbaa)

Bad object: { "flexGrow": 1, "alignItems": "center",
"justifyContent": "center", "backgroundColor": "rgba(0, 170, 255, 1)" } in ScrollView (at createAnimatedComponent.js:154)

In case you want to try it out yourself, the full component (and repo) is here: https://github.com/wim82/chapter-interview/blob/master/QuestionRotator.js

Upvotes: 0

Views: 8728

Answers (2)

Mike Martin
Mike Martin

Reputation: 4200

You can't animate any properties of contentContainerStyle of a scrollview because the underlying component, ScrollContentContainerViewClass, is hardcoded by react-native and can't be changed. See the source code here: https://github.com/facebook/react-native/blob/bbb6a0754ce4173e24d3c0b46a5350ff2a8690d3/Libraries/Components/ScrollView/ScrollView.js#L790-L802

You would need to open an issue and then submit a pull request adding a property to scrollView that would allow you to set ScrollContentContainerViewClass.

Upvotes: 0

Ravi Raj
Ravi Raj

Reputation: 6677

Apply the backgroundColor inside the style property instead of contentContainerStyle of scrollView.

The Animated.Value(0) should be stored in the state, not as a class object (from the official docs and best practice).

I have modified your above code to make it work,

import React, { Component } from 'react';
import { Text, StyleSheet, Animated } from 'react-native';

export default class App extends Component {


  constructor (props) {
    super(props);
    // Intialize to default value
    this.state = {
      backgroundColor: new Animated.Value(0)
    };
  }

  onPress = () => {
    // onPress, initialize to default value using setState and start animation
    // after the state has been updated
    this.setState({ backgroundColor: new Animated.Value(0) }, () => {
       Animated.timing(this.state.backgroundColor, {
        toValue: 100,
        duration: 5000
      }).start();
    });
  }


  render() {
    return (
      <Animated.ScrollView
        style={[
            styles.container,
            // Interpolation mapping from numbers to strings (colors)
            {
              backgroundColor: this.state.backgroundColor.interpolate({
                inputRange: [0, 100],
                outputRange: ["#00aaFF", "#808080"]
              })
            }
          ]}
      >
        <Text
          // onPress to start Animation
          onPress={() => this.onPress() }
          style={styles.paragraph}
        >
          Change code in the editor and watch it change on your phone!
          Save to get a shareable url.
        </Text>
      </Animated.ScrollView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
    color: '#34495e',
  },
});

Working snack example: https://snack.expo.io/BymzMdtRG

Hope this helps.

Upvotes: 3

Related Questions