Tabs animation and selected index fixes (#8377)

* fix(tabs): animation freeze when chaning tabs

* fix(tabs): poper item selecting programically
This commit is contained in:
Vasil Trifonov
2020-02-25 17:08:43 +02:00
committed by GitHub
parent e218ee12e7
commit acaabbd2aa
5 changed files with 36 additions and 20 deletions

View File

@ -2934,7 +2934,7 @@ export abstract class ViewBase extends Observable {
// (undocumented) // (undocumented)
_setupAsRootView(context: any): void; _setupAsRootView(context: any): void;
_setupUI(context: any /* android.content.Context */, atIndex?: number): void; _setupUI(context: any /* android.content.Context */, atIndex?: number): void;
_shouldDelayLoad(): boolean; _shouldDelayLayout(): boolean;
showModal(moduleName: string, modalOptions: ShowModalOptions): ViewBase; showModal(moduleName: string, modalOptions: ShowModalOptions): ViewBase;
showModal(view: ViewBase, modalOptions: ShowModalOptions): ViewBase; showModal(view: ViewBase, modalOptions: ShowModalOptions): ViewBase;
public readonly style: Style; public readonly style: Style;

View File

@ -474,7 +474,7 @@ export abstract class ViewBase extends Observable {
* When returning true the callLoaded method will be run in setTimeout * When returning true the callLoaded method will be run in setTimeout
* Method is intended to be overridden by inheritors and used as "protected" * Method is intended to be overridden by inheritors and used as "protected"
*/ */
_shouldDelayLoad(): boolean; _shouldDelayLayout(): boolean;
/** /**
* @private * @private

View File

@ -561,12 +561,24 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
} }
} }
private performLayout(currentRun = 0) {
// if there's an animation in progress we need to delay the layout
// we've added a guard of 5000 milliseconds execution
// to make sure that the layout will happen even if the animation haven't finished in 5 seconds
if (this._shouldDelayLayout() && currentRun < 100) {
setTimeout(() => this.performLayout(currentRun), currentRun);
currentRun++;
} else {
this.parent.requestLayout();
}
}
@profile @profile
public requestLayout(): void { public requestLayout(): void {
// Default implementation for non View instances (like TabViewItem). // Default implementation for non View instances (like TabViewItem).
const parent = this.parent; const parent = this.parent;
if (parent) { if (parent) {
parent.requestLayout(); this.performLayout();
} }
} }
@ -615,15 +627,11 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
public loadView(view: ViewBase): void { public loadView(view: ViewBase): void {
if (view && !view.isLoaded) { if (view && !view.isLoaded) {
if (this._shouldDelayLoad()) { view.callLoaded();
setTimeout(() => view.callLoaded());
} else {
view.callLoaded();
}
} }
} }
public _shouldDelayLoad(): boolean { public _shouldDelayLayout(): boolean {
return false; return false;
} }

View File

@ -348,7 +348,7 @@ export class Page extends PageBase {
// //
} }
public _shouldDelayLoad(): boolean { public _shouldDelayLayout(): boolean {
return this._frame && this._frame._animationInProgress; return this._frame && this._frame._animationInProgress;
} }

View File

@ -2,7 +2,7 @@
import { TabContentItem } from "../tab-navigation-base/tab-content-item"; import { TabContentItem } from "../tab-navigation-base/tab-content-item";
import { TabStrip } from "../tab-navigation-base/tab-strip"; import { TabStrip } from "../tab-navigation-base/tab-strip";
import { TabStripItem } from "../tab-navigation-base/tab-strip-item"; import { TabStripItem } from "../tab-navigation-base/tab-strip-item";
import { TextTransform } from "../text-base"; import { TextTransform, ViewBase } from "../text-base";
// Requires // Requires
import { Color } from "../../color"; import { Color } from "../../color";
@ -873,6 +873,9 @@ export class Tabs extends TabsBase {
// TODO: investigate why this call is necessary to actually toggle item appearance // TODO: investigate why this call is necessary to actually toggle item appearance
this.viewController.tabBar.sizeToFit(); this.viewController.tabBar.sizeToFit();
this.tabStrip.setNativeView(this.viewController.tabBar); this.tabStrip.setNativeView(this.viewController.tabBar);
if (this.selectedIndex) {
this.viewController.tabBar.setSelectedItemAnimated(this.tabBarItems[this.selectedIndex], false);
}
} }
// const length = items ? items.length : 0; // const length = items ? items.length : 0;
@ -1066,6 +1069,17 @@ export class Tabs extends TabsBase {
this._ios.tabBar.tintColor = nativeColor; this._ios.tabBar.tintColor = nativeColor;
} }
private visitFrames(view: ViewBase, operation: (frame: Frame) => {}) {
if (view instanceof Frame) {
operation(view);
}
view.eachChild(child => {
this.visitFrames(child, operation);
return true;
});
}
[selectedIndexProperty.setNative](value: number) { [selectedIndexProperty.setNative](value: number) {
// TODO // TODO
// if (traceEnabled()) { // if (traceEnabled()) {
@ -1092,17 +1106,11 @@ export class Tabs extends TabsBase {
this._currentNativeSelectedIndex = value; this._currentNativeSelectedIndex = value;
let itemControllerOwner = null; // do not make layout changes while the animation is in progress https://stackoverflow.com/a/47031524/613113
if (itemController._owner) { this.visitFrames(item, frame => frame._animationInProgress = true);
let itemControllerOwner = <Frame>itemController._owner.get();
// do not load new views while the animation is in progress https://stackoverflow.com/a/47031524/613113
itemControllerOwner._animationInProgress = true;
}
this.viewController.setViewControllersDirectionAnimatedCompletion(controllers, navigationDirection, true, (finished: boolean) => { this.viewController.setViewControllersDirectionAnimatedCompletion(controllers, navigationDirection, true, (finished: boolean) => {
if (itemControllerOwner) { this.visitFrames(item, frame => frame._animationInProgress = false);
itemControllerOwner._animationInProgress = false;
}
if (finished) { if (finished) {
// HACK: UIPageViewController fix; see https://stackoverflow.com/a/17330606 // HACK: UIPageViewController fix; see https://stackoverflow.com/a/17330606
invokeOnRunLoop(() => this.viewController.setViewControllersDirectionAnimatedCompletion(controllers, navigationDirection, false, null)); invokeOnRunLoop(() => this.viewController.setViewControllersDirectionAnimatedCompletion(controllers, navigationDirection, false, null));