Animate listview items when they are added/removed from datasource

Here you can get full working example for opacity animation:

import React from 'react-native';

export default class Cell extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            opacity: new React.Animated.Value(0)
        };
    }

    componentDidMount() {
        React.Animated.timing(this.state.opacity, {
            toValue: 1,
            duration: 250,
        }).start();
    }

    render() {
        return (
            <React.Animated.View style={[styles.wrapper, {opacity: this.state.opacity}]}>
                <React.Image source={{uri: 'http://placehold.it/150x150'}} style={styles.image}/>
                <React.Text style={styles.text}>
                    Text
                </React.Text>
            </React.Animated.View>
        );
    }
}

const styles = React.StyleSheet.create({
    wrapper: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'flex-start',
        alignItems: 'center',
    },
    image: {
        height: 40,
        width: 40,
        marginRight: 16,
        backgroundColor: '#C9D5E6'
    },
    text: {
        fontSize: 20
    }
});

Animation when added is easy, just use Animated in componentDidMount with your listRow , for example:

componentDidMount = ()=> {
    Animated.timing(this.state._rowOpacity, {
        toValue: 1,
        duration: 250,
    }).start()
}

Animate a component before unmount is much harder in react-native. You should set a handler for ListView. When dataSource changed, diff the data, start Animated to hide removed row, and set new dataSource for ListView.


In case you need for removing an item from the list, here's how to do the ListRow component:

class DynamicListRow extends Component {
   // these values will need to be fixed either within the component or sent through props
   _defaultHeightValue = 60;
   _defaultTransition  = 500;
   state = {
       _rowHeight  : new Animated.Value(this._defaultHeightValue),
       _rowOpacity : new Animated.Value(0)
   };
   componentDidMount() {
       Animated.timing(this.state._rowOpacity, {
           toValue  : 1,
           duration : this._defaultTransition
       }).start()
   }
   componentWillReceiveProps(nextProps) {
       if (nextProps.remove) {
           this.onRemoving(nextProps.onRemoving);
       } else {
// we need this for iOS because iOS does not reset list row style properties
           this.resetHeight()
       }
   }
   onRemoving(callback) {
       Animated.timing(this.state._rowHeight, {
           toValue  : 0,
           duration : this._defaultTransition
       }).start(callback);
   }
   resetHeight() {
       Animated.timing(this.state._rowHeight, {
           toValue  : this._defaultHeightValue,
           duration : 0
       }).start();
   }
   render() {
       return (
           <Animated.View
               style={{height: this.state._rowHeight, opacity: this.state._rowOpacity}}>
               {this.props.children}
           </Animated.View>
       );
   }
}

i've posted a complete tutorial to this question in this blog post. And it's explaining step by step what you need to do to accomplish both adding and removing an item and animate this process. For adding is pretty straight forward, but for removing looks like it's a little bit more complex. http://moduscreate.com/react-native-dynamic-animated-lists/

Tags:

React Native