Description
Description
Splitting this out from my comment here.
I have a pretty reliable reproduction where, if you start scrolling one direction then quickly fling in the opposite direction, the view will actually scroll in the first direction, instead of the flung direction—see attached video (where the last scroll indicates the expected behavior). I've seen similar weird behavior in other parts of a production app with other repros, but this one is the most consistent.
weird-scroll.mp4
I've tried reproducing with a plain Android
ScrollView
in a native Android app and everything works as expected. I started trying to copy some of the code from React Native's subclass ofScrollView
to see if I can reproduce in isolation, but no luck so far....
This is on a stock Pixel 4, Android 12, so no OEM fiddling involved
Version
0.68.2
Output of npx react-native info
System:
OS: macOS 12.4
CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
Memory: 1.17 GB / 64.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 18.4.0 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 8.12.1 - /usr/local/bin/npm
Watchman: 4.9.0 - /Users/daniel/.nix-profile/bin/watchman
Managers:
CocoaPods: 1.11.0 - /Users/daniel/.nix-profile/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 21.2, iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3
Android SDK:
API Levels: 30, 31, 32
Build Tools: 30.0.3
System Images: android-31 | Google Play Intel x86 Atom_64, android-32 | Google Play Intel x86 Atom_64
Android NDK: Not Found
IDEs:
Android Studio: 4.1 AI-201.8743.12.41.7042882
Xcode: 13.2.1/13C100 - /usr/bin/xcodebuild
Languages:
Java: 1.8.0_292 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 17.0.2 => 17.0.2
react-native: 0.68.2 => 0.68.2
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found
Steps to reproduce
Any ScrollView
does this for me on Pixel 4 / Android 12, including FlatList
, etc.
I've narrowed this down in isolation by slowly incorporating code from ReactNativeScrollView
into a native subclass of ScrollView
to these lines:
override fun fling(velocityY: Int) {
super.fling(velocityY)
// Workaround.
// On Android P if a ScrollView is inverted, we will get a wrong sign for
// velocityY (see https://issuetracker.google.com/issues/112385925).
// At the same time, mOnScrollDispatchHelper tracks the correct velocity direction.
//
// Hence, we can use the absolute value from whatever the OS gives
// us and use the sign of what mOnScrollDispatchHelper has tracked.
var signum = Math.signum(mOnScrollDispatchHelper.getYFlingVelocity())
if (signum == 0f) {
signum = Math.signum(velocityY.toFloat())
}
val correctedVelocityY = (Math.abs(velocityY) * signum).toInt()
In other words, this workaround seems to be causing its own issue. Given that Google has fixed the bug, should we just skip this sign adjustment on versions > P
? I suspect the fundamental problem is that the computation triggered in onScrollChanged
is insufficient to catch these sorts of velocity changes, and OnScrollDispatchHelper
is not interacting with onTouchEvent
at all, so it may be sitting on stale data. It's perhaps a sufficient fix for broken platform versions, but it would probably be best to just use the native velocity tracking on versions where it isn't broken, if possible.
Snack, code example, screenshot, or link to a repository
https://snack.expo.dev/5wqtEIix2
Plus see the video linked above.
Activity