Search code examples
react-nativeanimationlayout-animation

React Native's LayoutAnimation animates only some of the UI elements, others jump


This has been tested using React Native 0.59 and 0.60.4 (latest):

As you can see, everything is animated except the title, which just hops to its new position.

This was created by the following code:

import React, { Component } from 'react';
import {
    SafeAreaView,
    StyleSheet,
    View,
    Text,
    TouchableOpacity,
    LayoutAnimation,
} from 'react-native';

export class App extends Component {

    constructor() {
        super();

        this.state = {
            expanded: false,
        }
    }

    render () {
        let headerStyle = Object.assign({}, styles.header);
        if (this.state.expanded) {
            headerStyle.height = 90;
        }
        return (
            <View style={styles.container}>
                <SafeAreaView></SafeAreaView>
                <View style={headerStyle}>
                    <Text style={styles.headerText}>My Title</Text>
                    <TouchableOpacity style={styles.expandButton} onPress={() => this.toggle()}>
                        <Text>
                            Animate
                        </Text>
                    </TouchableOpacity>
                </View>
                <View style={styles.list}>
                    <TouchableOpacity key={"1"} style={styles.listitem}>
                        <Text>Item 1</Text>
                    </TouchableOpacity>
                    <TouchableOpacity key={"2"} style={styles.listitem}>
                        <Text>Item 2</Text>
                    </TouchableOpacity>
                </View>
            </View>
        );
    }

    toggle() {
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
        this.setState({
            expanded: !this.state.expanded,
        })
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'flex-start',
        alignItems: 'stretch',
        backgroundColor: 'white',
    },
    header: {
        height: 120,
        //backgroundColor: 'red',
        justifyContent: 'flex-end',
    },
    headerText: {
        padding: 20,
        fontSize: 24,
        //backgroundColor: 'orange',
    },
    expandButton: {
        height: 40,
        borderRadius: 20,
        position: 'absolute',
        right: 15,
        bottom: 10,
        paddingHorizontal: 10,
        paddingVertical: 9,
    },
    list: {
        flex: 1,
        justifyContent: 'flex-start',
        alignItems: 'stretch',
        backgroundColor: 'white',
    },
    listitem: {
        height: 50,
        paddingHorizontal: 20,
        paddingVertical: 10,
    },
});

export default App;

Is that a React Native bug, or am I doing something wrong?


Solution

  • LayoutAnimation handles animating the position of elements - since you're changing the height of the header, its position is not changing. You would have to update your render tree in such a way on state.expanded that the header element changes its position instead of its height. The change in height of the header causes the position of the other elements to change which is why it works for them.

    Adding a spacer view above the header view that changes its height instead of the header view itself would work I believe.