Skip to content

Commit 2338339

Browse files
committed
fix(nav): improve reliability of swipe back gesture when quickly swiping back
1 parent ba2f49b commit 2338339

File tree

1 file changed

+36
-5
lines changed

1 file changed

+36
-5
lines changed

core/src/components/nav/nav.tsx

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { VIEW_STATE_ATTACHED, VIEW_STATE_DESTROYED, VIEW_STATE_NEW, convertToVie
3131
export class Nav implements NavOutlet {
3232
private transInstr: TransitionInstruction[] = [];
3333
private sbAni?: Animation;
34-
private animationEnabled = true;
34+
private gestureOrAnimationInProgress = false;
3535
private useRouter = false;
3636
private isTransitioning = false;
3737
private destroyed = false;
@@ -869,7 +869,36 @@ export class Nav implements NavOutlet {
869869
// or if it is a portal (modal, actionsheet, etc.)
870870
const opts = ti.opts!;
871871

872-
const progressCallback = opts.progressAnimation ? (ani: Animation | undefined) => (this.sbAni = ani) : undefined;
872+
const progressCallback = opts.progressAnimation
873+
? (ani: Animation | undefined) => {
874+
/**
875+
* Because this progress callback is called asynchronously
876+
* it is possible for the gesture to start and end before
877+
* the animation is ever set. In that scenario, we should
878+
* immediately call progressEnd so that the transition promise
879+
* resolves and the gesture does not get locked up.
880+
*/
881+
if (ani !== undefined && !this.gestureOrAnimationInProgress) {
882+
this.gestureOrAnimationInProgress = true;
883+
ani.onFinish(
884+
() => {
885+
this.gestureOrAnimationInProgress = false;
886+
},
887+
{ oneTimeCallback: true }
888+
);
889+
890+
/**
891+
* Playing animation to beginning
892+
* with a duration of 0 prevents
893+
* any flickering when the animation
894+
* is later cleaned up.
895+
*/
896+
ani.progressEnd(0, 0, 0);
897+
} else {
898+
this.sbAni = ani;
899+
}
900+
}
901+
: undefined;
873902
const mode = getIonMode(this);
874903
const enteringEl = enteringView.element!;
875904
const leavingEl = leavingView && leavingView.element!;
@@ -1008,15 +1037,16 @@ export class Nav implements NavOutlet {
10081037

10091038
private canStart(): boolean {
10101039
return (
1040+
!this.gestureOrAnimationInProgress &&
10111041
!!this.swipeGesture &&
10121042
!this.isTransitioning &&
10131043
this.transInstr.length === 0 &&
1014-
this.animationEnabled &&
10151044
this.canGoBackSync()
10161045
);
10171046
}
10181047

10191048
private onStart() {
1049+
this.gestureOrAnimationInProgress = true;
10201050
this.pop({ direction: 'back', progressAnimation: true });
10211051
}
10221052

@@ -1028,10 +1058,9 @@ export class Nav implements NavOutlet {
10281058

10291059
private onEnd(shouldComplete: boolean, stepValue: number, dur: number) {
10301060
if (this.sbAni) {
1031-
this.animationEnabled = false;
10321061
this.sbAni.onFinish(
10331062
() => {
1034-
this.animationEnabled = true;
1063+
this.gestureOrAnimationInProgress = false;
10351064
},
10361065
{ oneTimeCallback: true }
10371066
);
@@ -1055,6 +1084,8 @@ export class Nav implements NavOutlet {
10551084
}
10561085

10571086
this.sbAni.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
1087+
} else {
1088+
this.gestureOrAnimationInProgress = false;
10581089
}
10591090
}
10601091

0 commit comments

Comments
 (0)