mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-26 11:17:04 +08:00
fix(android): nested frames were sometimes not recreated (#9725)
BREAKING CHANGE: AndroidFragmentCallbacks now requires onResume as well Migration steps: specify onResume on custom fragment implementations
This commit is contained in:

committed by
Nathan Walker

parent
638388244e
commit
902a4c6afc
@ -19,6 +19,10 @@ const FragmentClass = (<any>org.nativescript.widgets.FragmentBase).extend('com.t
|
||||
this._callbacks.onPause(this, superProto.onPause);
|
||||
},
|
||||
|
||||
onResume(): void {
|
||||
this._callbacks.onResume(this, superProto.onResume);
|
||||
},
|
||||
|
||||
onCreate(savedInstanceState: android.os.Bundle) {
|
||||
if (!this._callbacks) {
|
||||
setFragmentCallbacks(this);
|
||||
|
@ -51,6 +51,7 @@ export interface ExpandedEntry extends BackstackEntry {
|
||||
frameId: number;
|
||||
|
||||
isNestedDefaultTransition: boolean;
|
||||
isAnimationRunning: boolean;
|
||||
}
|
||||
|
||||
export function _setAndroidFragmentTransitions(animated: boolean, navigationTransition: NavigationTransition, currentEntry: ExpandedEntry, newEntry: ExpandedEntry, frameId: number, fragmentTransaction: androidx.fragment.app.FragmentTransaction, isNestedDefaultTransition?: boolean): void {
|
||||
@ -60,6 +61,7 @@ export function _setAndroidFragmentTransitions(animated: boolean, navigationTran
|
||||
if (entries && entries.size > 0) {
|
||||
throw new Error('Calling navigation before previous navigation finish.');
|
||||
}
|
||||
newEntry.isAnimationRunning = false;
|
||||
|
||||
allowTransitionOverlap(currentFragment);
|
||||
allowTransitionOverlap(newFragment);
|
||||
@ -227,6 +229,7 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener {
|
||||
if (Trace.isEnabled()) {
|
||||
Trace.write(`START ${animator.transitionType} for ${entry.fragmentTag}`, Trace.categories.Transition);
|
||||
}
|
||||
entry.isAnimationRunning = true;
|
||||
}
|
||||
|
||||
onAnimationRepeat(animator: ExpandedAnimator): void {
|
||||
@ -239,6 +242,7 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener {
|
||||
if (Trace.isEnabled()) {
|
||||
Trace.write(`END ${animator.transitionType} for ${animator.entry.fragmentTag}`, Trace.categories.Transition);
|
||||
}
|
||||
animator.entry.isAnimationRunning = false;
|
||||
transitionOrAnimationCompleted(animator.entry, animator.backEntry);
|
||||
}
|
||||
|
||||
@ -246,6 +250,7 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener {
|
||||
if (Trace.isEnabled()) {
|
||||
Trace.write(`CANCEL ${animator.transitionType} for ${animator.entry.fragmentTag}`, Trace.categories.Transition);
|
||||
}
|
||||
animator.entry.isAnimationRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,6 +237,21 @@ export class Frame extends FrameBase {
|
||||
this.backgroundColor = this._originalBackground;
|
||||
this._originalBackground = null;
|
||||
}
|
||||
setTimeout(() => {
|
||||
// there's a bug with nested frames where sometimes the nested fragment is not recreated at all
|
||||
// so we manually check on loaded event if the fragment is not recreated and recreate it
|
||||
const currentEntry = this._currentEntry || this._executingContext?.entry;
|
||||
if (currentEntry) {
|
||||
if (!currentEntry.fragment) {
|
||||
const manager = this._getFragmentManager();
|
||||
const transaction = manager.beginTransaction();
|
||||
currentEntry.fragment = this.createFragment(currentEntry, currentEntry.fragmentTag);
|
||||
_updateTransitions(currentEntry);
|
||||
transaction.replace(this.containerViewId, currentEntry.fragment, currentEntry.fragmentTag);
|
||||
transaction.commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
|
||||
super.onLoaded();
|
||||
}
|
||||
@ -1002,6 +1017,19 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
public onResume(fragment: org.nativescript.widgets.FragmentBase, superFunc: Function): void {
|
||||
const frame = this.entry.resolvedPage.frame;
|
||||
// on some cases during the first navigation on nested frames the animation doesn't trigger
|
||||
// we depend on the animation (even None animation) to set the entry as the current entry
|
||||
// animation should start between start and resume, so if we have an executing navigation here it probably means the animation was skipped
|
||||
// so we manually set the entry
|
||||
if (frame._executingContext && !(<any>this.entry).isAnimationRunning) {
|
||||
frame.setCurrent(this.entry, frame._executingContext.navigationType);
|
||||
}
|
||||
superFunc.call(fragment);
|
||||
}
|
||||
|
||||
@profile
|
||||
public onStop(fragment: androidx.fragment.app.Fragment, superFunc: Function): void {
|
||||
superFunc.call(fragment);
|
||||
|
1
packages/core/ui/frame/index.d.ts
vendored
1
packages/core/ui/frame/index.d.ts
vendored
@ -476,6 +476,7 @@ export interface AndroidFragmentCallbacks {
|
||||
onDestroyView(fragment: any, superFunc: Function): void;
|
||||
onDestroy(fragment: any, superFunc: Function): void;
|
||||
onPause(fragment: any, superFunc: Function): void;
|
||||
onResume(fragment: any, superFunc: Function): void;
|
||||
onStop(fragment: any, superFunc: Function): void;
|
||||
toStringOverride(fragment: any, superFunc: Function): string;
|
||||
}
|
||||
|
Reference in New Issue
Block a user