question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AnimatedFlatList's scroll and drag performance - Reanimated2

See original GitHub issue

Description

AnimatedFlatList’s scroll and drag performance seems poor. I’m just using opacity and scale property for animation with interpolation. During scroll performance was not good but if I was dragging slowly, ui thread performance was descending so dramatically. Did I miss something? My test device is iPhone6s

Screenshots

gifflatlist

Steps To Reproduce

See code below. You can copy and paste to any project, it will work.

Expected behavior

Smooth 60fps opacity and scale animation.

Actual behavior

2-30 fps animation 😦

Snack or minimal code example

import React from 'react';
import {StyleSheet, FlatList, View, Text, Dimensions} from 'react-native';
import Animated, {
  Extrapolate,
  interpolate,
  useAnimatedScrollHandler,
  useAnimatedStyle,
  useSharedValue,
} from 'react-native-reanimated';

const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);

const items = [
  {id: 1, text: 'A'},
  {id: 2, text: 'B'},
  {id: 3, text: 'C'},
  {id: 4, text: 'D'},
  {id: 5, text: 'E'},
  {id: 6, text: 'F'},
  {id: 7, text: 'G'},
  {id: 8, text: 'H'},
  {id: 9, text: 'I'},
  {id: 10, text: 'J'},
  {id: 11, text: 'K'},
  {id: 12, text: 'L'},
];

const {width: SCREEN_WIDTH} = Dimensions.get('window');
const ITEM_WIDTH = SCREEN_WIDTH / 5;
const data = [...items, ...items, ...items];

export const Home = () => {
  const transX = useSharedValue(0);

  const renderItem = ({item, index}) => {
    return <Item index={index} item={item} transX={transX} />;
  };

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (event) => {
      transX.value = event.contentOffset.x;
    },
  });

  return (
    <View style={styles.container}>
      <View style={styles.listContainer}>
        <AnimatedFlatList
          onScroll={scrollHandler}
          horizontal
          showsHorizontalScrollIndicator={false}
          style={styles.list}
          data={data}
          decelerationRate="fast"
          centerContent
          snapToInterval={ITEM_WIDTH}
          scrollEventThrottle={16}
          pagingEnabled
          snapToAlignment="center"
          renderItem={renderItem}
          keyExtractor={(item, index) => `${item.id}-${index}`}
        />
      </View>
    </View>
  );
};

const Item = ({index, item, transX}) => {
  const animatedStyle = useAnimatedStyle(() => {
    return {
      opacity: opacityAnimation(transX, index),
      transform: [
        {
          scale: scaleAnimation(transX, index),
        },
      ],
    };
  });
  return (
    <Animated.View style={[styles.box, animatedStyle]} item={item}>
      <Text style={styles.label}>{item.text}</Text>
    </Animated.View>
  );
};

const scaleAnimation = (transX, index) => {
  'worklet';

  return interpolate(
    transX.value,
    [
      (index - 2) * ITEM_WIDTH,
      (index - 1) * ITEM_WIDTH,
      index * ITEM_WIDTH,
      (index + 1) * ITEM_WIDTH,
      (index + 2) * ITEM_WIDTH,
    ],
    [0.5, 0.7, 1, 0.7, 0.5],
    Extrapolate.CLAMP,
  );
};

const opacityAnimation = (transX, index) => {
  'worklet';

  return interpolate(
    transX.value,
    [
      (index - 3) * ITEM_WIDTH,
      (index - 2) * ITEM_WIDTH,
      (index - 1) * ITEM_WIDTH,
      index * ITEM_WIDTH,
      (index + 1) * ITEM_WIDTH,
      (index + 2) * ITEM_WIDTH,
      (index + 3) * ITEM_WIDTH,
    ],
    [0, 0.5, 0.8, 1, 0.8, 0.5, 0],
    Extrapolate.CLAMP,
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#efefef',
  },
  listContainer: {
    height: ITEM_WIDTH + 250,
    alignItems: 'center',
    justifyContent: 'center',
  },
  list: {
    height: ITEM_WIDTH * 2,
    flexGrow: 0,
    paddingHorizontal: ITEM_WIDTH * 2,
  },
  box: {
    width: ITEM_WIDTH,
    height: ITEM_WIDTH,
    backgroundColor: 'blue',
    borderRadius: 20,
    alignItems: 'center',
    justifyContent: 'center',
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 6,
    },
    shadowOpacity: 0.37,
    shadowRadius: 7.49,

    elevation: 12,
  },
  label: {
    fontWeight: 'bold',
    fontSize: 24,
    color: '#fff',
  },
});

Package versions

  • React: 16.13.1
  • React Native: 0.63.3
  • React Native Reanimated: 2.0.0-rc.0
  • NodeJS: 14.4.0

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:18 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
vance-liucommented, Jan 12, 2021

Video: normal-video

3reactions
ysfzrncommented, Dec 9, 2020

I also added getItemLayout to FlatList with useCallbacks, animation increased to 60 fps 🥳 🥳 🥳

  //...
  const renderItem = useCallback(({item, index}) => {
    return <Item index={index} item={item} transX={transX} />;
  }, []);

  const keyExtractor = useCallback((item, index) => `${item.id}-${index}`, []);
  const getItemLayout = useCallback(
    (data, index) => ({
      length: ITEM_WIDTH,
      offset: ITEM_WIDTH * index,
      index,
    }),
    [],
  );

  //...
Read more comments on GitHub >

github_iconTop Results From Across the Web

useAnimatedScrollHandler | React Native Reanimated
This is a convenience hook that returns an event handler reference which can be used with React Native's scrollable components.
Read more >
Animations - React Native
React Native provides two complementary animation systems: Animated ... ScrollView , FlatList and SectionList , but you can also create your ...
Read more >
react-native-draggable-flatlist - npm
React Native Draggable FlatList. A drag-and-drop-enabled FlatList component for React Native. Fully native interactions powered by Reanimated ...
Read more >
Unanswered 'react-native-reanimated-v2' Questions - Page 2
React Native Gesture Handler + Reanimated Flat List Scroll. I'm having a problem with react-native-gesture handler animation in a FlatList. when i try...
Read more >
Scrollable Bottom Sheet with virtualisation, native animations ...
You can scroll the list to the top and drag the bottom sheet down on the ... Inifinite scrolling onboarding animation made with...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found