Using Animated.Flatlist and Animated.ScrollView to animate an Animated.View is not smooth

12k views Asked by At

I am would like to make an animated header.

  1. I Created an animated component of FlatList,
  2. Used the onScroll function to update the animated value.
  3. Placed a view (Animated.View) as the header above the animated FlatList using position absolute.
  4. Finally, interpolate the animated value to change the view (Animated.View) using transform properties.

The animation works fine, but the animation is not smooth at all.

I saw this issue of how using scrollEventThrottle helps the smoothness. So I thought using FlatList would be smooth but it's not. If your scroll while pressing, it's smooth. But if you scroll and leave the finger, it's jumpy ( I don't know how to describe it. Sorry). The scrolling is smooth but the animated view (Header) animation is not smooth at all.

Environment

  • react: 16.0.0-alpha.12,
  • react-native: ^0.47.0,
  • node: v7.7.3
  • npm: 4.1.2
  • yarn: 0.21.3

Target Platform: iOS and Android

Build tools: expo

Link to snack demo

export default class AnimatedHeader extends React.Component {
 state = {
  animatedValue: new Animated.Value(0),
 };
 
 _renderItem = ({item}) => {
  return (
   <View style={styles.nonsenseItem}>
    <Text style={styles.itemText}>{item}</Text>
   </View>
  )
 };
 
 render() {
  let scaleY = this.state.animatedValue.interpolate({
   inputRange: [0, 180],
   outputRange: [1, 0.5],
   extrapolate: 'clamp',
  });
  
  let translateY = this.state.animatedValue.interpolate({
   inputRange: [0, 180],
   outputRange: [0, -100],
   extrapolate: 'clamp',
  });
  
  return (
   <View style={styles.container}>
    <AnimatedFlatList
     contentContainerStyle={{marginTop: 200}}
     scrollEventThrottle={16} // <-- Use 1 here to make sure no events are ever missed
     onScroll={Animated.event(
      [{nativeEvent: {contentOffset: {y: this.state.animatedValue}}}],
      {useNativeDriver: true} // <-- Add this
     )}
     data={data}
     renderItem={this._renderItem}
     keyExtractor={(item, i) => i}/>
    <Animated.View style={[styles.headerWrapper, {transform: [{scaleY}, {translateY}]}]}/>
   </View>
  )
 }
}

Update

So, I tried to implement the same functionality using ScrollView. However, I think, its event worse using ScrollView when compared to FlatList.

Here is the expo snack demo: Animated ScrollView Header

I think I need to mention how I got here at the first place. So, I tried to implement this by a very nice tutorial in Medium, and also by watching this awesome youtube react conf viedo by Brent. However, the exact code used on youtube video has the same effect. Also, on the Medium tutorial, the author has given a Link to his expo Animated header link, which works very smoothly. But the same code doesn't work smoothly when I copy paste the code. So, I think the problem is with the react or react native version. I will update if I have any new update. Thank you.

1

There are 1 answers

4
bend On BEST ANSWER

There has been a regression in React Native 0.46 which, fortunately, has been fixed in 0.48.2 (see this issue and this PR). That's why you're having the issue with recent Expo versions. I've had this problem with custom parallax images, and this was solved by building a custom binary with RN 0.48.3.

Your code is fine, even though I would recommend setting scrollEventThrottle to 1 as this really helps smoothing things out on iOS.