Search code examples
react-nativereact-native-reanimated

React Native : Bad performance animating the height of a view using react-native-reanimated


Animating the height of a view when scrolling through a list is very slow and choppy, it's work fine for IOS, but not for Android :

import * as React from "react";
import { StyleSheet, Text } from "react-native";
import Animated from "react-native-reanimated";
const { Value, View, ScrollView, interpolate, Extrapolate } = Animated;
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "black"
  },
  listView: {
    flex: 1
  }
});

const IMAGE_MIN_HEIGHT = 300;

export default () => {
  const animation = new Value(0);

  const height = interpolate(animation, {
    inputRange: [0, 125],
    outputRange: [IMAGE_MIN_HEIGHT, 125],
    extrapolate: Extrapolate.CLAMP
  });

  return (
    <View style={styles.container}>
      <View
        style={{
          backgroundColor: "red",
          height: height,
          width: "100%"
        }}
      ></View>
      <ScrollView
        onScroll={Animated.event([
          {
            nativeEvent: {
              contentOffset: {
                y: animation
              }
            }
          }
        ])}
        scrollEventThrottle={1}
        style={[styles.listView]}
      >
        {[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].map((elem, index) => (
          <View
            style={{ width: "100%", height: 100, marginBottom: 20 }}
            key={index}
          >
            <Text style={{ color: "white", fontSize: 30 }}>{elem}</Text>
          </View>
        ))}
      </ScrollView>
    </View>
  );
};

Is there anything that can be done to make it smoother?


Solution

  • the solution is to set Header position to absolute, i don't know why but it's working fine :

    import * as React from "react";
    import { StyleSheet, Text, Platform } from "react-native";
    import Animated from "react-native-reanimated";
    const { Value, View, ScrollView, interpolate, Extrapolate } = Animated;
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: "black"
      },
      listView: {
        flex: 1
      }
    });
    
    const IMAGE_MIN_HEIGHT = 300;
    
    export default () => {
      const animation = new Value(0);
    
      const height = interpolate(animation, {
        inputRange: [0, 125],
        outputRange: [IMAGE_MIN_HEIGHT, 125],
        extrapolate: Extrapolate.CLAMP
      });
    
      return (
        <View style={styles.container}>
          <ScrollView
            contentContainerStyle={{ paddingTop: IMAGE_MIN_HEIGHT }}
            onScroll={Animated.event([
              {
                nativeEvent: {
                  contentOffset: {
                    y: animation
                  }
                }
              }
            ])}
            scrollEventThrottle={1}
            style={[styles.listView]}
          >
            {[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].map((elem, index) => (
              <View
                style={{ width: "100%", height: 100, marginBottom: 20 }}
                key={index}
              >
                <Text style={{ color: "white", fontSize: 30 }}>{elem}</Text>
              </View>
            ))}
          </ScrollView>
    
          <View
            style={{
              backgroundColor: "red",
              height: height,
              width: "100%",
              position: "absolute",
              top: Platform.OS == "ios" ? 20 : 0,
              left: 0,
              right: 0
            }}
          ></View>
        </View>
      );
    };