Repository: react-native
Issue: Scrolling a 'moving' FlatList causes it to stutter or block scrolling completely on Android
Labels: Issue: Author Provided Repro,Platform: Android,Component: FlatList,Needs: Triage :mag:,Needs: Attention

### Description

When you create a FlatList that moves as it's being scrolled (change in offset for the FlatList is a change in `top` property of FlatList's style) it stutters heavily. This behavior is much less disruptive when movement is scaled down compared to scrolling and becomes app-breaking when upscaled. See provided videos:

1. Multiplier: 1.0
[mult1.webm](https://github.com/facebook/react-native/assets/40713406/b8ca27d7-7ddc-42d9-8763-941620569a52)
2. Mutliplier: 2.0
[mult2.webm](https://github.com/facebook/react-native/assets/40713406/9487f743-d0cd-49f8-93c1-2c8cdaff2bbc)
3. Multiplier: 0.5
[mult0.5.webm](https://github.com/facebook/react-native/assets/40713406/38829f21-613b-4fc3-bb09-c9288b78d20a)

It was originally an [issue in react-native-reanimated](https://github.com/software-mansion/react-native-reanimated/issues/4625) but after digging into it I narrowed it down to `react-native` and rewrote the code to not use react-native-reanimated. It seems to had been in the code for a long time, since [this posts that dates 3 years back](https://www.reddit.com/r/reactnative/comments/hynq2f/trying_to_achieve_ios_like_header_in_android_but/) is about the same thing.

I checked it on versions 0.72, 0.71 and 0.70. On both Fabric and Paper and the result is always the same (although it feels a bit like Fabric behaviour is worse).

iOS works properly on each version too.

It seems like there is a problem when calculating layout and touch events - that's what I conducted due to `multiplier` making it better or worse. After moving a FlatList twice the distance it scrolled and having the component moved React Native seems to 'think' that the finger is now further than it should be and lowers the offset? That's just my guess.

### React Native Version

0.72.3

### Output of `npx react-native info`

System:
  OS: macOS 13.4.1
  CPU: (10) arm64 Apple M2 Pro
  Memory: 49.31 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.16.0
    path: /var/folders/jg/m839qn593nn7w_h3n0r9k25c0000gn/T/yarn--1689593442476-0.9098900178237601/node
  Yarn:
    version: 1.22.19
    path: /var/folders/jg/m839qn593nn7w_h3n0r9k25c0000gn/T/yarn--1689593442476-0.9098900178237601/yarn
  npm:
    version: 9.5.1
    path: ~/.nvm/versions/node/v18.16.0/bin/npm
  Watchman:
    version: 2023.06.12.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.12.1
    path: /Users/user/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 22.4
      - iOS 16.4
      - macOS 13.3
      - tvOS 16.4
      - watchOS 9.4
  Android SDK: Not Found
IDEs:
  Android Studio: 2022.1 AI-221.6008.13.2211.9619390
  Xcode:
    version: 14.3.1/14E300c
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 11.0.19
    path: /usr/bin/javac
  Ruby:
    version: 3.2.2
    path: /Users/user/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.72.3
    wanted: 0.72.3
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: false

### Steps to reproduce

Just need to run the provided code snippet.

### Snack, code example, screenshot, or link to a repository

https://github.com/tjzel/ReactNativeMovingFlatList

```TSX
import React from 'react';
import {Dimensions, FlatList, StyleSheet, Text, View} from 'react-native';

const {height: SCREEN_HEIGHT} = Dimensions.get('screen');

const data = Array.from({length: 30}, (_, index) => ({
  id: `${index + 1}`,
  text: `Item ${index + 1}`,
}));

const multiplier = 1.0;

export default function App() {
  const [animatedVerticalScroll, setAnimatedVerticalScroll] = React.useState(0);
  // used to detect stutters
  const previousValue = React.useRef(0);

  const listAnimatedStyle = {
    top:
      animatedVerticalScroll * multiplier > SCREEN_HEIGHT * 0.7
        ? 0
        : SCREEN_HEIGHT * 0.7 - animatedVerticalScroll * multiplier,
  };

  const renderItem = ({item}) => (
    <View style={styles.item}>
      <Text>{item.text}</Text>
    </View>
  );

  const scrollHandler = event => {
    // logger to detect if there was a stutter
    if (previousValue.current > event.nativeEvent.contentOffset.y) {
      console.log(
        `\nScrolling stuttered!\nPrevious offset was ${previousValue.current}\nCurrent offset is ${event.nativeEvent.contentOffset.y}\n`,
      );
    } else {
      console.log(event.nativeEvent.contentOffset.y);
    }
    setAnimatedVerticalScroll(event.nativeEvent.contentOffset.y);
    previousValue.current = event.nativeEvent.contentOffset.y;
  };

  return (
    <View style={styles.container}>
      <View style={styles.containerBehind}>
        <Text>Multiplier: {multiplier}</Text>
      </View>
      <FlatList
        data={data}
        renderItem={renderItem}
        style={[styles.listContainer, listAnimatedStyle]}
        onScroll={scrollHandler}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  containerBehind: {
    width: '100%',
    height: '100%',
    flex: 1,
    backgroundColor: 'red',
    alignItems: 'center',
    justifyContent: 'center',
  },
  listContainer: {
    top: 0,
    left: 0,
    position: 'absolute',
    zIndex: 10,
    width: '100%',
    height: '100%',
    backgroundColor: 'green',
  },
  item: {
    height: 50,
  },
});
```