Skip to content

Commit

Permalink
Add JS detection for momentum scroll event computation
Browse files Browse the repository at this point in the history
Summary:
In D65556000, a bug was introduced that can sometimes fire `onMomentumScrollBegin` directly after `onMomentumScrollEnd`, leading the `ScrollView` to believe it's in the "animating" state. In this state, the `ScrollView` will tell the gesture responder system that it intends to handle touch events, preventing any child components from receiving touches.

Changelog: [Internal]

Reviewed By: andrewdacenko

Differential Revision: D66453988
  • Loading branch information
Abbondanzo authored and facebook-github-bot committed Nov 27, 2024
1 parent 7f57018 commit b1a3a8a
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
VScrollContentViewNativeComponent,
VScrollViewNativeComponent,
} from '../../../src/private/components/VScrollViewNativeComponents';
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
import AnimatedImplementation from '../../Animated/AnimatedImplementation';
import FrameRateLogger from '../../Interaction/FrameRateLogger';
import {findNodeHandle} from '../../ReactNative/RendererProxy';
Expand Down Expand Up @@ -658,6 +659,7 @@ type State = {|
|};

const IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16;
const IS_ANIMATING_TIME_BETWEEN_MOMENTUM_SCROLLS_MS = 3;

export type ScrollViewComponentStatics = $ReadOnly<{|
Context: typeof ScrollViewContext,
Expand Down Expand Up @@ -1306,6 +1308,17 @@ class ScrollView extends React.Component<Props, State> {
const isAnimating =
timeSinceLastMomentumScrollEnd < IS_ANIMATING_TOUCH_START_THRESHOLD_MS ||
this._lastMomentumScrollEndTime < this._lastMomentumScrollBeginTime;
// This is a hack to prevent issues with momentum scroll begin firing directly after momentum scroll end
if (ReactNativeFeatureFlags.enableScrollViewMomentumGapFix()) {
const timeBetweenMomentumScrolls = Math.abs(
this._lastMomentumScrollEndTime - this._lastMomentumScrollBeginTime,
);
return (
isAnimating &&
timeBetweenMomentumScrolls >
IS_ANIMATING_TIME_BETWEEN_MOMENTUM_SCROLLS_MS
);
}
return isAnimating;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,15 @@ const definitions: FeatureFlagDefinitions = {
purpose: 'release',
},
},
enableScrollViewMomentumGapFix: {
defaultValue: false,
metadata: {
dateAdded: '2024-11-25',
description:
'Enables a temporary fix to prevent scroll momentum events from keeping the scroll view in an animated state',
purpose: 'experimentation',
},
},
fixVirtualizeListCollapseWindowSize: {
defaultValue: false,
metadata: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<38ad29621eeb29a9f82735dc187c13d4>>
* @generated SignedSource<<992ef8d0dc0d1a6d4dc8685fc7b1c74e>>
* @flow strict
*/

Expand Down Expand Up @@ -36,6 +36,7 @@ export type ReactNativeFeatureFlagsJsOnly = {
enableAnimatedAllowlist: Getter<boolean>,
enableAnimatedClearImmediateFix: Getter<boolean>,
enableAnimatedPropsMemo: Getter<boolean>,
enableScrollViewMomentumGapFix: Getter<boolean>,
fixVirtualizeListCollapseWindowSize: Getter<boolean>,
isLayoutAnimationEnabled: Getter<boolean>,
shouldSkipStateUpdatesForLoopingAnimations: Getter<boolean>,
Expand Down Expand Up @@ -144,6 +145,11 @@ export const enableAnimatedClearImmediateFix: Getter<boolean> = createJavaScript
*/
export const enableAnimatedPropsMemo: Getter<boolean> = createJavaScriptFlagGetter('enableAnimatedPropsMemo', true);

/**
* Enables a temporary fix to prevent scroll momentum events from keeping the scroll view in an animated state
*/
export const enableScrollViewMomentumGapFix: Getter<boolean> = createJavaScriptFlagGetter('enableScrollViewMomentumGapFix', false);

/**
* Fixing an edge case where the current window size is not properly calculated with fast scrolling. Window size collapsed to 1 element even if windowSize more than the current amount of elements
*/
Expand Down

0 comments on commit b1a3a8a

Please sign in to comment.