Skip to content

Commit ca2a6d2

Browse files
authored
Merge pull request #202 from hsource/harry-fix-autoscroll
Fixed autoscroll being stuck when already scrolled to top/bottom
2 parents 21f9ae1 + 4cc0775 commit ca2a6d2

4 files changed

Lines changed: 77 additions & 30 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"react": "^16.12.0",
4848
"react-native": "^0.61.5",
4949
"react-native-gesture-handler": "^1.5.3",
50-
"react-native-reanimated": "^1.7.0",
50+
"react-native-reanimated": "^1.9.0",
5151
"typescript": "^3.7.3"
5252
}
5353
}

src/index.tsx

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ class DraggableFlatList<T> extends React.Component<Props<T>, State> {
226226

227227
keyToIndex = new Map<string, number>();
228228

229+
/** Whether we've sent an incomplete call to the FlatList to do a scroll */
229230
isAutoscrolling = {
230231
native: new Value<number>(0),
231232
js: false
@@ -611,23 +612,49 @@ class DraggableFlatList<T> extends React.Component<Props<T>, State> {
611612
return targetOffset;
612613
};
613614

614-
autoscroll = async ([
615-
distFromTop,
616-
distFromBottom,
617-
scrollOffset,
618-
isScrolledUp,
619-
isScrolledDown
620-
]: readonly number[]) => {
621-
const targetOffset = this.getScrollTargetOffset(
622-
distFromTop,
623-
distFromBottom,
624-
scrollOffset,
625-
!!isScrolledUp,
626-
!!isScrolledDown
627-
);
628-
if (targetOffset >= 0 && this.isPressedIn.js) {
629-
const nextScrollParams = await this.scrollToAsync(targetOffset);
630-
this.autoscroll(nextScrollParams);
615+
/** Ensure that only 1 call to autoscroll is active at a time */
616+
autoscrollLooping = false;
617+
autoscroll = async (params: readonly number[]) => {
618+
if (this.autoscrollLooping) {
619+
return;
620+
}
621+
this.autoscrollLooping = true;
622+
try {
623+
let shouldScroll = true;
624+
let curParams = params;
625+
while (shouldScroll) {
626+
const [
627+
distFromTop,
628+
distFromBottom,
629+
scrollOffset,
630+
isScrolledUp,
631+
isScrolledDown
632+
] = curParams;
633+
const targetOffset = this.getScrollTargetOffset(
634+
distFromTop,
635+
distFromBottom,
636+
scrollOffset,
637+
!!isScrolledUp,
638+
!!isScrolledDown
639+
);
640+
const scrollingUpAtTop = !!(
641+
isScrolledUp && targetOffset <= scrollOffset
642+
);
643+
const scrollingDownAtBottom = !!(
644+
isScrolledDown && targetOffset >= scrollOffset
645+
);
646+
shouldScroll =
647+
targetOffset >= 0 &&
648+
this.isPressedIn.js &&
649+
!scrollingUpAtTop &&
650+
!scrollingDownAtBottom;
651+
652+
if (shouldScroll) {
653+
curParams = await this.scrollToAsync(targetOffset);
654+
}
655+
}
656+
} finally {
657+
this.autoscrollLooping = false;
631658
}
632659
};
633660

@@ -669,17 +696,26 @@ class DraggableFlatList<T> extends React.Component<Props<T>, State> {
669696
and(
670697
this.isAutoscrolling.native,
671698
or(
699+
// We've scrolled to where we want to be
672700
lessOrEq(
673701
abs(sub(this.targetScrollOffset, this.scrollOffset)),
674702
scrollPositionTolerance
675703
),
676-
this.isScrolledUp,
677-
this.isScrolledDown
704+
// We're at the start, but still want to scroll farther up
705+
and(
706+
this.isScrolledUp,
707+
lessOrEq(this.targetScrollOffset, this.scrollOffset)
708+
),
709+
// We're at the end, but still want to scroll further down
710+
and(
711+
this.isScrolledDown,
712+
greaterOrEq(this.targetScrollOffset, this.scrollOffset)
713+
)
678714
)
679715
),
680716
[
717+
// Finish scrolling
681718
set(this.isAutoscrolling.native, 0),
682-
this.checkAutoscroll,
683719
call(this.autoscrollParams, this.onAutoscrollComplete)
684720
]
685721
)
@@ -779,7 +815,10 @@ class DraggableFlatList<T> extends React.Component<Props<T>, State> {
779815
[`translate${horizontal ? "X" : "Y"}`]: this
780816
.hoverComponentTranslate
781817
}
782-
]
818+
// We need the cast because the transform array usually accepts
819+
// only specific keys, and we dynamically generate the key
820+
// above
821+
] as Animated.AnimatedTransform
783822
}
784823
]}
785824
>

src/procs.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import Animated from "react-native-reanimated";
2-
import { State as GestureState } from "react-native-gesture-handler";
32

43
let {
54
or,
@@ -68,9 +67,16 @@ export const hardReset = proc(
6867
block([set(position, 0), set(finished, 0), set(time, 0), set(toValue, 0)])
6968
);
7069

71-
export const setupCell = proc(
70+
/**
71+
* The in react-native-reanimated.d.ts definition of `proc` only has generics
72+
* for up to 10 arguments. We cast it to accept any params to avoid errors when
73+
* type-checking.
74+
*/
75+
type RetypedProc = (cb: (...params: any) => Animated.Node<number>) => typeof cb;
76+
77+
export const setupCell = (proc as RetypedProc)(
7278
(
73-
currentIndex: Animated.Node<number>,
79+
currentIndex: Animated.Value<number>,
7480
initialized: Animated.Value<number>,
7581
size: Animated.Node<number>,
7682
offset: Animated.Node<number>,
@@ -207,7 +213,7 @@ export const setupCell = proc(
207213
])
208214
);
209215

210-
const betterSpring = proc(
216+
const betterSpring = (proc as RetypedProc)(
211217
(
212218
finished: Animated.Value<number>,
213219
velocity: Animated.Value<number>,

yarn.lock

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3740,10 +3740,12 @@ react-native-gesture-handler@^1.5.3:
37403740
invariant "^2.2.4"
37413741
prop-types "^15.7.2"
37423742

3743-
react-native-reanimated@^1.7.0:
3744-
version "1.7.0"
3745-
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-1.7.0.tgz#896db2576552ac59d288a1f6c7f00afc171f240c"
3746-
integrity sha512-FQWSqP605eQVJumuK2HpR+7heF0ZI+qfy4jNguv3Xv8nPFHeIgZaRTXHCEQL2AcuSIj50zy8jGJf5l134QMQWQ==
3743+
react-native-reanimated@^1.9.0:
3744+
version "1.9.0"
3745+
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-1.9.0.tgz#38676c99dd585504fdc7331efb45e5f48ec7339a"
3746+
integrity sha512-Aj+spgIHRiVv7ezGADxnSH1EoKrQRD2+XaSiGY0MiB/pvRNNrZPSJ+3NVpvLwWf9lZMOP7dwqqyJIzoZgBDt8w==
3747+
dependencies:
3748+
fbjs "^1.0.0"
37473749

37483750
react-native@^0.61.5:
37493751
version "0.61.5"

0 commit comments

Comments
 (0)