Skip to content

Commit 82768f7

Browse files

File tree

1 file changed

+45
-48
lines changed

1 file changed

+45
-48
lines changed

Libraries/Lists/VirtualizedList.js

Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const {findNodeHandle} = require('../ReactNative/RendererProxy');
4747
const flattenStyle = require('../StyleSheet/flattenStyle');
4848
const StyleSheet = require('../StyleSheet/StyleSheet');
4949
const infoLog = require('../Utilities/infoLog');
50+
const Platform = require('../Utilities/Platform');
5051
const FillRateHelper = require('./FillRateHelper');
5152
const ViewabilityHelper = require('./ViewabilityHelper');
5253
const invariant = require('invariant');
@@ -1034,6 +1035,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
10341035
_totalCellsMeasured = 0;
10351036
_updateCellsToRenderBatcher: Batchinator;
10361037
_viewabilityTuples: Array<ViewabilityHelperCallbackTuple> = [];
1038+
_hasDoneFirstScroll = false;
10371039

10381040
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
10391041
* LTI update could not be added via codemod */
@@ -1320,71 +1322,62 @@ class VirtualizedList extends React.PureComponent<Props, State> {
13201322
initialScrollIndex,
13211323
enabledTalkbackCompatibleInvertedList,
13221324
} = this.props;
1323-
const {contentLength, visibleLength, offset} = this._scrollMetrics;
1325+
const {contentLength, visibleLength, offset, dOffset} = this._scrollMetrics;
13241326
const talkbackCompatibility =
13251327
this.state.screenreaderEnabled &&
13261328
initialScrollIndex == null &&
13271329
inverted &&
13281330
enabledTalkbackCompatibleInvertedList;
13291331
let distanceFromEnd;
1332+
let endPositionReached;
1333+
let startPositionReached;
1334+
let isScrollingForward = dOffset < 0;
1335+
// in case of inverted flatlist with talkback enabled
1336+
// replace 2 with threeshold
1337+
const THRESHOLD = Platform.OS === 'android' ? 2 : 30;
13301338
if (talkbackCompatibility && this._hasTriggeredInitialScrollToIndex) {
13311339
distanceFromEnd = offset;
1340+
startPositionReached =
1341+
Math.abs(visibleLength + offset - contentLength) < THRESHOLD;
1342+
endPositionReached = Math.abs(offset) < THRESHOLD;
13321343
} else {
13331344
distanceFromEnd = contentLength - visibleLength - offset;
1345+
endPositionReached =
1346+
Math.abs(visibleLength + offset - contentLength) < THRESHOLD;
1347+
startPositionReached = Math.abs(offset) < THRESHOLD;
13341348
}
13351349

1336-
// Especially when oERT is zero it's necessary to 'floor' very small distanceFromEnd values to be 0
1337-
// since debouncing causes us to not fire this event for every single "pixel" we scroll and can thus
1338-
// be at the "end" of the list with a distanceFromEnd approximating 0 but not quite there.
1339-
if (!talkbackCompatibility && distanceFromEnd < ON_END_REACHED_EPSILON) {
1340-
distanceFromEnd = 0;
1341-
}
1342-
1343-
// TODO: T121172172 Look into why we're "defaulting" to a threshold of 2 when oERT is not present
1344-
const threshold =
1345-
onEndReachedThreshold != null ? onEndReachedThreshold * visibleLength : 2;
1346-
const canTriggerOnEndReachedWithTalkback =
1347-
typeof this._lastTimeOnEndReachedCalled === 'number'
1348-
? Math.abs(this._lastTimeOnEndReachedCalled - Date.now()) > 500
1349-
: true;
13501350
if (
1351-
onEndReached &&
1352-
this._beginningReached &&
13531351
talkbackCompatibility &&
1354-
distanceFromEnd === 0 &&
1355-
this._hasTriggeredInitialScrollToIndex &&
1356-
this.state.last === getItemCount(data) - 1 &&
1357-
this._scrollMetrics.contentLength !== this._sentEndForContentLength &&
1358-
canTriggerOnEndReachedWithTalkback
1352+
startPositionReached &&
1353+
!this._hasDoneFirstScroll
13591354
) {
1360-
// save the last position in the flastlist to restore it after animation to Top
1361-
this._lastOffsetFromBottomOfScreen = this._offsetFromBottomOfScreen;
1362-
// Only call onEndReached once for a given content length
1363-
this._sentEndForContentLength = this._scrollMetrics.contentLength;
1364-
// wait 100 ms to call again onEndReached (TalkBack scrolling is slower)
1365-
this._lastTimeOnEndReachedCalled = Date.now();
1366-
onEndReached({distanceFromEnd});
1367-
} else {
1368-
this._lastOffsetFromBottomOfScreen = undefined;
1355+
return;
13691356
}
1370-
if (
1371-
onEndReached &&
1372-
this.state.last === getItemCount(data) - 1 &&
1373-
distanceFromEnd <= threshold &&
1374-
this._scrollMetrics.contentLength !== this._sentEndForContentLength
1375-
) {
1376-
if (talkbackCompatibility) {
1377-
this._beginningReached = true;
1378-
} else {
1379-
// Only call onEndReached once for a given content length
1380-
this._sentEndForContentLength = this._scrollMetrics.contentLength;
1381-
onEndReached({distanceFromEnd});
1382-
}
1383-
} else if (distanceFromEnd > threshold) {
1384-
// If the user scrolls away from the end and back again cause
1385-
// an onEndReached to be triggered again
1386-
this._sentEndForContentLength = 0;
1357+
1358+
// If scrolled up in the vertical list
1359+
if (dOffset < 0) {
1360+
return;
1361+
}
1362+
1363+
// If contentLength has not changed
1364+
if (contentLength === this._sentEndForContentLength) {
1365+
return;
13871366
}
1367+
1368+
// If the distance is so farther than the area shown on the screen
1369+
if (distanceFromEnd >= visibleLength * 1.5) {
1370+
return;
1371+
}
1372+
1373+
// $FlowFixMe
1374+
const minimumDistanceFromEnd = onEndReachedThreshold * visibleLength;
1375+
if (distanceFromEnd >= minimumDistanceFromEnd) {
1376+
return;
1377+
}
1378+
1379+
this._sentEndForContentLength = contentLength;
1380+
onEndReached({distanceFromEnd});
13881381
}
13891382

13901383
_onContentSizeChange = (width: number, height: number) => {
@@ -1445,12 +1438,15 @@ class VirtualizedList extends React.PureComponent<Props, State> {
14451438
this._lastScrollPosition === undefined ||
14461439
this._lastItem === undefined ||
14471440
(lastItemDidNotChange && scrollPositionChanged);
1441+
console.log('triggerTalkbackScrollToEnd:', triggerTalkbackScrollToEnd);
1442+
console.log('talkbackCompatibility:', talkbackCompatibility);
14481443
if (
14491444
width > 0 &&
14501445
height > 0 &&
14511446
triggerTalkbackScrollToEnd &&
14521447
talkbackCompatibility
14531448
) {
1449+
console.log('scroll to the end');
14541450
// onMomentumScrollEnd does not work with TalkBack gestures
14551451
// estrapolate this to a method talkbackScrollTo compatible with
14561452
// TalkBack gestures.
@@ -1613,6 +1609,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
16131609
if (!this.props) {
16141610
return;
16151611
}
1612+
this._hasDoneFirstScroll = true;
16161613
this._maybeCallOnEndReached();
16171614
if (velocity !== 0) {
16181615
this._fillRateHelper.activate();

0 commit comments

Comments
 (0)