-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scrolling a 'moving' FlatList causes it to stutter or block scrolling completely on Android #38470
Comments
Could you put your snippet in this repro template @tjzel and attach it to this issue? |
Sure, it's added! |
Just a sidenote, I’ve seen this happening with |
Hey folks, is this PR responsible for this? |
After building from source with the above PR included it's even worse @ryancat: demo videoScreen.Recording.2023-07-18.at.10.02.03.mov |
@efstathiosntonas #38475 is meant to support props that allow ScrollView to get throttled. If not used it should have no effect on ScrollView. I'll take a look to see why it's making any differences here. |
Thanks for the clarification @ryancat. Are there any updates on this one @cortinico? |
No updates. We're happy to receive a PR that fixes this (so it's up for grab) |
VirtualizedList is defaulting I thought about dropping the default for Android, but on iOS we've been having the same default already. It's the right thing to do to align both platforms and to have a default so that we can improve native frame rate. If you feel the throttle is working against your use case, you may set a lower value (any value less than 17 should have no effect on throttling). |
I think we should remove this default, even though it was previously set on iOS. It is going to be incorrect for the vast majority of use-cases. Users shouldn't need to know on an RN update that they now need to set an obscure prop to a lower value. Time-based throttling has other issues as well (and VirtualizedList already has a mechanism to avoid starvation). |
Separate from the throttling, we should not be adding new code to React Native which is hardcoded to assume 60fps. This is not correct on many devices, including even older or lower end Android devices. |
Summary: This is specific to the scenario, and device, and time-based sampling as implemented on Android may inherently create stutters because we may not proess events at a consistent cadence (and we may never process the last events). facebook#38475 made this code no longer no-op on Android, which caused scroll regressions documented in facebook#38470 We are already coalescing scroll events on both Android and iOS, which will ensure we are not flooded with events. Though after this change, it is possible some heavy scenarios will see more time dedicated to FlatList work after this. Changelog: [General][Changed] - Remove default 50ms Scroll Event Throttling in VirtualizedList Differential Revision: D47823772 fbshipit-source-id: 8e78f2349c1a8134908a2e190368b8f84ff84e06
…ook#38648) Summary: Pull Request resolved: facebook#38648 This is specific to the scenario, and device, and time-based sampling as implemented on Android may inherently create stutters because we may not proess events at a consistent cadence (and we may never process the last events). facebook#38475 made this code no longer no-op on Android, which caused regressions documented in facebook#38470 due to VirtualizedList having more out-of-date information. We are already coalescing scroll events on both Android and iOS, which will ensure we are not flooded with events. VirtualizedList also already inserts an artificial 50ms delay to new renders by default when high priority work is not happening (see `updateCellsBatchingPeriod`). This limits the heavy work done by VirtualizedList (no new renders or expensive math on scroll events), while letting the list still have the most recent events. We can eventually remove this once VirtualizedList is able to use OffScreen universally. Changelog: [General][Changed] - Remove default 50ms Scroll Event Throttling in VirtualizedList Differential Revision: D47823772 fbshipit-source-id: c3cbd81bdd74ade79ec050b6ef02c4d0c43f4db2
…ook#38648) Summary: Pull Request resolved: facebook#38648 This is specific to the scenario, and device, and time-based sampling as implemented on Android may inherently create stutters because we may not proess events at a consistent cadence (and we may never process the last events). facebook#38475 made this code no longer no-op on Android, which caused regressions documented in facebook#38470 (comment) due to VirtualizedList having more out-of-date information. We are already coalescing scroll events on both Android and iOS, which will ensure we are not flooded with events. VirtualizedList also already inserts an artificial 50ms delay to new renders by default when high priority work is not happening (see `updateCellsBatchingPeriod`). This limits the heavy work done by VirtualizedList (no new renders or expensive math on scroll events), while letting the list still have the most recent events. We can eventually remove this once VirtualizedList is able to use OffScreen universally. Changelog: [General][Changed] - Remove default 50ms Scroll Event Throttling in VirtualizedList Differential Revision: D47823772 fbshipit-source-id: 0abf312b9cf5c5f25457b58f4b8cbb393789b14d
Anecdotally, I am aware of some code which implements a similar scenario and it seems to work okay on Android. Their implementation looks like:
|
@NickGerleman I removed
|
@NickGerleman Yeah there are several workarounds for this and by no means my code is made to be efficient - while using |
|
I ended up running into this with the above PR. Some components like This specific behavior and expectation is a bit quirky, and is probably some artifact of RN back in the day being written for iOS before Android, and the two diverging. I am kind of tempted to try to run an experiment to change this behavior in the new architecture (maybe not worth the churn to change behavior in Paper). |
@NickGerleman thanks for support on this, we've tried using Using demo, modified to: import React from 'react';
import {Animated, Dimensions, StyleSheet, Text, View} from 'react-native';
const {height: SCREEN_HEIGHT} = Dimensions.get('screen');
const data = Array.from({length: 60}, (_, index) => ({
id: `${index + 1}`,
text: `Item ${index + 1}`,
}));
const App = () => {
const scrollY = new Animated.Value(0);
const translateY = scrollY.interpolate({
inputRange: [0, SCREEN_HEIGHT],
outputRange: [SCREEN_HEIGHT * 0.7, 0],
extrapolate: 'extend',
});
const renderItem = ({item}) => (
<View style={styles.item}>
<Text>{item.text}</Text>
</View>
);
return (
<View style={styles.container}>
<View style={styles.containerBehind}>
<Text>Multiplier: 1.0</Text>
</View>
<Animated.FlatList
data={data}
renderItem={renderItem}
style={[
styles.listContainer,
{
transform: [{translateY}],
paddingTop: scrollY,
},
]}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: scrollY}}}],
{useNativeDriver: false},
)}
ListFooterComponent={<Animated.View style={{height: scrollY}} />}
scrollEventThrottle={16}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
containerBehind: {
width: '100%',
height: '100%',
flex: 1,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center',
},
listContainer: {
left: 0,
position: 'absolute',
zIndex: 10,
width: '100%',
height: '100%',
backgroundColor: 'green',
},
item: {
height: 50,
},
});
export default App; |
…ook#38648) Summary: Pull Request resolved: facebook#38648 facebook#38475 made this code no longer no-op on Android, which caused regressions documented in facebook#38470 (comment) due to VirtualizedList having more out-of-date information. We are already coalescing scroll events on both Android and iOS, which will ensure we are not flooded with events. VirtualizedList also already inserts an artificial 50ms delay to new renders by default when high priority work is not happening (see `updateCellsBatchingPeriod`). This limits the heavy work done by VirtualizedList (no new renders or expensive math on scroll events), while letting the list still have the most recent events. We can eventually remove this once VirtualizedList is able to use OffScreen universally. Changelog: [General][Changed] - Remove default 50ms Scroll Event Throttling in VirtualizedList Reviewed By: ryancat Differential Revision: D47823772 fbshipit-source-id: bf0befb1b9146e2173069c484735dc287b956e37
…ook#38648) Summary: Pull Request resolved: facebook#38648 facebook#38475 made this code no longer no-op on Android, which caused regressions documented in facebook#38470 (comment) due to VirtualizedList having more out-of-date information. We are already coalescing scroll events on both Android and iOS, which will ensure we are not flooded with events. VirtualizedList also already inserts an artificial 50ms delay to new renders by default when high priority work is not happening (see `updateCellsBatchingPeriod`). This limits the heavy work done by VirtualizedList (no new renders or expensive math on scroll events), while letting the list still have the most recent events. We can eventually remove this once VirtualizedList is able to use OffScreen universally. Changelog: [General][Changed] - Remove default 50ms Scroll Event Throttling in VirtualizedList Reviewed By: ryancat Differential Revision: D47823772 fbshipit-source-id: 5f538b7531a1907d4831fdb81ea0cda56af38bd2
…ook#38648) Summary: Pull Request resolved: facebook#38648 facebook#38475 made this code no longer no-op on Android, which caused regressions documented in facebook#38470 (comment) due to VirtualizedList having more out-of-date information. We are already coalescing scroll events on both Android and iOS, which will ensure we are not flooded with events. VirtualizedList also already inserts an artificial 50ms delay to new renders by default when high priority work is not happening (see `updateCellsBatchingPeriod`). This limits the heavy work done by VirtualizedList (no new renders or expensive math on scroll events), while letting the list still have the most recent events. We can eventually remove this once VirtualizedList is able to use OffScreen universally. Changelog: [General][Changed] - Remove default 50ms Scroll Event Throttling in VirtualizedList Reviewed By: ryancat Differential Revision: D47823772 fbshipit-source-id: dc6290ad02f9cbd40429270fc878d51cbb9b56b9
Summary: Pull Request resolved: #38648 #38475 made this code no longer no-op on Android, which caused regressions documented in #38470 (comment) due to VirtualizedList having more out-of-date information. We are already coalescing scroll events on both Android and iOS, which will ensure we are not flooded with events. VirtualizedList also already inserts an artificial 50ms delay to new renders by default when high priority work is not happening (see `updateCellsBatchingPeriod`). This limits the heavy work done by VirtualizedList (no new renders or expensive math on scroll events), while letting the list still have the most recent events. We can eventually remove this once VirtualizedList is able to use OffScreen universally. Changelog: [General][Changed] - Remove default 50ms Scroll Event Throttling in VirtualizedList Reviewed By: ryancat Differential Revision: D47823772 fbshipit-source-id: 55d22a1074235ccc1b2cf167f6b1758640c79edb
Hey @NickGerleman, have you had the time to look into this? I built an app with nightly RN version and it seems the issue is still there. |
It still persist. Is there any update @NickGerleman |
I guess onScroll event has missing layout calculation, the list height is increase if another view height decrease which outside of the list(padding leads bug in this case). IOS side has no recalculation of the list height during scroll so there is no stuttering |
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:mult1.webm
mult2.webm
mult0.5.webm
It was originally an issue in react-native-reanimated 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 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
The text was updated successfully, but these errors were encountered: