mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-03 11:44:40 +08:00
fix(core): RootLayout shade cover asynchronous execution (#10228)
This commit is contained in:
committed by
GitHub
parent
6779cdcb55
commit
a19568c0d0
@ -42,7 +42,9 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
|
|
||||||
// ability to add any view instance to composite views like layers
|
// ability to add any view instance to composite views like layers
|
||||||
open(view: View, options: RootLayoutOptions = {}): Promise<void> {
|
open(view: View, options: RootLayoutOptions = {}): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
const enterAnimationDefinition = options.animation ? options.animation.enterFrom : null;
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
if (!(view instanceof View)) {
|
if (!(view instanceof View)) {
|
||||||
return reject(new Error(`Invalid open view: ${view}`));
|
return reject(new Error(`Invalid open view: ${view}`));
|
||||||
}
|
}
|
||||||
@ -51,8 +53,9 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
return reject(new Error(`${view} has already been added`));
|
return reject(new Error(`${view} has already been added`));
|
||||||
}
|
}
|
||||||
|
|
||||||
const enterAnimationDefinition = options.animation ? options.animation.enterFrom : null;
|
resolve();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
// keep track of the views locally to be able to use their options later
|
// keep track of the views locally to be able to use their options later
|
||||||
this.popupViews.push({ view: view, options: options });
|
this.popupViews.push({ view: view, options: options });
|
||||||
|
|
||||||
@ -61,15 +64,16 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
// we just update properties if needed by additional overlaid views
|
// we just update properties if needed by additional overlaid views
|
||||||
if (this.shadeCover) {
|
if (this.shadeCover) {
|
||||||
// overwrite current shadeCover options if topmost popupview has additional shadeCover configurations
|
// overwrite current shadeCover options if topmost popupview has additional shadeCover configurations
|
||||||
this.updateShadeCover(this.shadeCover, options.shadeCover);
|
return this.updateShadeCover(this.shadeCover, options.shadeCover);
|
||||||
} else {
|
|
||||||
this.openShadeCover(options.shadeCover);
|
|
||||||
}
|
}
|
||||||
|
return this.openShadeCover(options.shadeCover);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
view.opacity = 0; // always begin with view invisible when adding dynamically
|
view.opacity = 0; // always begin with view invisible when adding dynamically
|
||||||
this.insertChild(view, this.getChildrenCount() + 1);
|
this.insertChild(view, this.getChildrenCount() + 1);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// only apply initial state and animate after the first tick - ensures safe areas and other measurements apply correctly
|
// only apply initial state and animate after the first tick - ensures safe areas and other measurements apply correctly
|
||||||
this.applyInitialState(view, enterAnimationDefinition);
|
this.applyInitialState(view, enterAnimationDefinition);
|
||||||
@ -85,12 +89,21 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// optional animation parameter to overwrite close animation declared when opening popup
|
// optional animation parameter to overwrite close animation declared when opening popup
|
||||||
// ability to remove any view instance from composite views
|
// ability to remove any view instance from composite views
|
||||||
close(view: View, exitTo?: TransitionAnimation): Promise<void> {
|
close(view: View, exitTo?: TransitionAnimation): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
const cleanupAndFinish = () => {
|
||||||
|
view.notify({ eventName: 'closed', object: view });
|
||||||
|
this.removeChild(view);
|
||||||
|
};
|
||||||
|
|
||||||
|
// use exitAnimation that is passed in and fallback to the exitAnimation passed in when opening
|
||||||
|
let exitAnimationDefinition = exitTo;
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
if (!(view instanceof View)) {
|
if (!(view instanceof View)) {
|
||||||
return reject(new Error(`Invalid close view: ${view}`));
|
return reject(new Error(`Invalid close view: ${view}`));
|
||||||
}
|
}
|
||||||
@ -99,15 +112,15 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
return reject(new Error(`Unable to close popup. ${view} not found`));
|
return reject(new Error(`Unable to close popup. ${view} not found`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
const popupIndex = this.getPopupIndex(view);
|
const popupIndex = this.getPopupIndex(view);
|
||||||
const poppedView = this.popupViews[popupIndex];
|
const poppedView = this.popupViews[popupIndex];
|
||||||
const cleanupAndFinish = () => {
|
|
||||||
view.notify({ eventName: 'closed', object: view });
|
if (!exitAnimationDefinition) {
|
||||||
this.removeChild(view);
|
exitAnimationDefinition = poppedView?.options?.animation?.exitTo;
|
||||||
resolve();
|
}
|
||||||
};
|
|
||||||
// use exitAnimation that is passed in and fallback to the exitAnimation passed in when opening
|
|
||||||
const exitAnimationDefinition = exitTo || poppedView?.options?.animation?.exitTo;
|
|
||||||
|
|
||||||
// Remove view from tracked popupviews
|
// Remove view from tracked popupviews
|
||||||
this.popupViews.splice(popupIndex, 1);
|
this.popupViews.splice(popupIndex, 1);
|
||||||
@ -117,33 +130,33 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
if (!poppedView?.options?.shadeCover?.ignoreShadeRestore) {
|
if (!poppedView?.options?.shadeCover?.ignoreShadeRestore) {
|
||||||
const shadeCoverOptions = this.popupViews[this.popupViews.length - 1]?.options?.shadeCover;
|
const shadeCoverOptions = this.popupViews[this.popupViews.length - 1]?.options?.shadeCover;
|
||||||
if (shadeCoverOptions) {
|
if (shadeCoverOptions) {
|
||||||
this.updateShadeCover(this.shadeCover, shadeCoverOptions);
|
return this.updateShadeCover(this.shadeCover, shadeCoverOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove shade cover animation if this is the last opened popup view
|
// remove shade cover animation if this is the last opened popup view
|
||||||
if (this.popupViews.length === 0) {
|
if (this.popupViews.length === 0) {
|
||||||
this.closeShadeCover(poppedView?.options?.shadeCover);
|
return this.closeShadeCover(poppedView?.options?.shadeCover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
if (exitAnimationDefinition) {
|
if (exitAnimationDefinition) {
|
||||||
this.getExitAnimation(view, exitAnimationDefinition)
|
return this.getExitAnimation(view, exitAnimationDefinition)
|
||||||
.play()
|
.play()
|
||||||
.then(cleanupAndFinish.bind(this))
|
.then(cleanupAndFinish.bind(this))
|
||||||
.catch((ex) => {
|
.catch((ex) => Promise.reject(new Error(`Error playing exit animation: ${ex}`)));
|
||||||
reject(new Error(`Error playing exit animation: ${ex}`));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cleanupAndFinish();
|
|
||||||
}
|
}
|
||||||
|
cleanupAndFinish();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
closeAll(): Promise<void[]> {
|
closeAll(): Promise<void[]> {
|
||||||
const toClose = [];
|
const toClose = [];
|
||||||
|
const views = this.popupViews.map((popupView) => popupView.view);
|
||||||
|
|
||||||
// Close all views at the same time and wait for all of them
|
// Close all views at the same time and wait for all of them
|
||||||
while (this.popupViews.length > 0) {
|
for (const view of views) {
|
||||||
toClose.push(this.close(this.popupViews[this.popupViews.length - 1].view));
|
toClose.push(this.close(view));
|
||||||
}
|
}
|
||||||
return Promise.all(toClose);
|
return Promise.all(toClose);
|
||||||
}
|
}
|
||||||
@ -342,7 +355,7 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
return shadeCover;
|
return shadeCover;
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateShadeCover(shade: View, shadeOptions: ShadeCoverOptions = {}): void {
|
private updateShadeCover(shade: View, shadeOptions: ShadeCoverOptions = {}): Promise<void> {
|
||||||
if (shadeOptions.tapToClose !== undefined && shadeOptions.tapToClose !== null) {
|
if (shadeOptions.tapToClose !== undefined && shadeOptions.tapToClose !== null) {
|
||||||
shade.off('tap');
|
shade.off('tap');
|
||||||
if (shadeOptions.tapToClose) {
|
if (shadeOptions.tapToClose) {
|
||||||
@ -351,7 +364,7 @@ export class RootLayoutBase extends GridLayout {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._updateShadeCover(shade, shadeOptions);
|
return this._updateShadeCover(shade, shadeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasChild(view: View): boolean {
|
private hasChild(view: View): boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user