mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-08 15:51:16 +08:00
fix(nav): improve reliability of swipe back gesture when quickly swiping back (#27904)
Issue number: resolves #27893 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> This is another instance of https://github.com/ionic-team/ionic-framework/issues/22895. The `progressCallback` function is fires asynchronously, so it's possible for the gesture start and end callbacks to run before the animation is ever set in `progressCallback`. When this happens, the animation gets locked up. I previously fixed this in https://github.com/ionic-team/ionic-framework/pull/23527 for `ion-router-outlet`, but I did not fix it for `ion-nav`. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - If the gesture has ended by the time `progressCallback` fires, reset the animation to the beginning so it does not get locked up. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Dev build: `7.2.2-dev.11690896715.12338339`
This commit is contained in:
@ -31,7 +31,7 @@ import { VIEW_STATE_ATTACHED, VIEW_STATE_DESTROYED, VIEW_STATE_NEW, convertToVie
|
||||
export class Nav implements NavOutlet {
|
||||
private transInstr: TransitionInstruction[] = [];
|
||||
private sbAni?: Animation;
|
||||
private animationEnabled = true;
|
||||
private gestureOrAnimationInProgress = false;
|
||||
private useRouter = false;
|
||||
private isTransitioning = false;
|
||||
private destroyed = false;
|
||||
@ -869,7 +869,36 @@ export class Nav implements NavOutlet {
|
||||
// or if it is a portal (modal, actionsheet, etc.)
|
||||
const opts = ti.opts!;
|
||||
|
||||
const progressCallback = opts.progressAnimation ? (ani: Animation | undefined) => (this.sbAni = ani) : undefined;
|
||||
const progressCallback = opts.progressAnimation
|
||||
? (ani: Animation | undefined) => {
|
||||
/**
|
||||
* Because this progress callback is called asynchronously
|
||||
* it is possible for the gesture to start and end before
|
||||
* the animation is ever set. In that scenario, we should
|
||||
* immediately call progressEnd so that the transition promise
|
||||
* resolves and the gesture does not get locked up.
|
||||
*/
|
||||
if (ani !== undefined && !this.gestureOrAnimationInProgress) {
|
||||
this.gestureOrAnimationInProgress = true;
|
||||
ani.onFinish(
|
||||
() => {
|
||||
this.gestureOrAnimationInProgress = false;
|
||||
},
|
||||
{ oneTimeCallback: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* Playing animation to beginning
|
||||
* with a duration of 0 prevents
|
||||
* any flickering when the animation
|
||||
* is later cleaned up.
|
||||
*/
|
||||
ani.progressEnd(0, 0, 0);
|
||||
} else {
|
||||
this.sbAni = ani;
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
const mode = getIonMode(this);
|
||||
const enteringEl = enteringView.element!;
|
||||
const leavingEl = leavingView && leavingView.element!;
|
||||
@ -1008,15 +1037,16 @@ export class Nav implements NavOutlet {
|
||||
|
||||
private canStart(): boolean {
|
||||
return (
|
||||
!this.gestureOrAnimationInProgress &&
|
||||
!!this.swipeGesture &&
|
||||
!this.isTransitioning &&
|
||||
this.transInstr.length === 0 &&
|
||||
this.animationEnabled &&
|
||||
this.canGoBackSync()
|
||||
);
|
||||
}
|
||||
|
||||
private onStart() {
|
||||
this.gestureOrAnimationInProgress = true;
|
||||
this.pop({ direction: 'back', progressAnimation: true });
|
||||
}
|
||||
|
||||
@ -1028,10 +1058,9 @@ export class Nav implements NavOutlet {
|
||||
|
||||
private onEnd(shouldComplete: boolean, stepValue: number, dur: number) {
|
||||
if (this.sbAni) {
|
||||
this.animationEnabled = false;
|
||||
this.sbAni.onFinish(
|
||||
() => {
|
||||
this.animationEnabled = true;
|
||||
this.gestureOrAnimationInProgress = false;
|
||||
},
|
||||
{ oneTimeCallback: true }
|
||||
);
|
||||
@ -1055,6 +1084,8 @@ export class Nav implements NavOutlet {
|
||||
}
|
||||
|
||||
this.sbAni.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
|
||||
} else {
|
||||
this.gestureOrAnimationInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user