mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
perf: reduce amount of layout calls and debounce layouts when needed (#10164)
This commit is contained in:
@@ -211,7 +211,6 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
const boundsOrigin = nativeView.bounds.origin;
|
||||
const boundsFrame = adjustedFrame || frame;
|
||||
nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, boundsFrame.size.width, boundsFrame.size.height);
|
||||
nativeView.layoutIfNeeded();
|
||||
|
||||
this._raiseLayoutChangedEvent();
|
||||
this._isLaidOut = true;
|
||||
@@ -889,6 +888,9 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
}
|
||||
|
||||
_setNativeClipToBounds() {
|
||||
if (!this.nativeViewProtected) {
|
||||
return;
|
||||
}
|
||||
const backgroundInternal = this.style.backgroundInternal;
|
||||
this.nativeViewProtected.clipsToBounds = (this.nativeViewProtected instanceof UIScrollView || backgroundInternal.hasBorderWidth() || backgroundInternal.hasBorderRadius()) && !backgroundInternal.hasBoxShadow();
|
||||
}
|
||||
|
||||
@@ -14,9 +14,51 @@ const majorVersion = iOSNativeHelper.MajorVersion;
|
||||
class UILayoutViewController extends UIViewController {
|
||||
public owner: WeakRef<View>;
|
||||
|
||||
private _isRunningLayout: number;
|
||||
private get isRunningLayout() {
|
||||
return this._isRunningLayout !== 0;
|
||||
}
|
||||
private startRunningLayout() {
|
||||
this._isRunningLayout++;
|
||||
}
|
||||
private finishRunningLayout() {
|
||||
this._isRunningLayout--;
|
||||
this.clearScheduledLayout();
|
||||
}
|
||||
private runLayout(cb: () => void) {
|
||||
try {
|
||||
this.startRunningLayout();
|
||||
cb();
|
||||
} finally {
|
||||
this.finishRunningLayout();
|
||||
}
|
||||
}
|
||||
|
||||
layoutTimer: number;
|
||||
|
||||
private clearScheduledLayout() {
|
||||
if (this.layoutTimer) {
|
||||
clearTimeout(this.layoutTimer);
|
||||
this.layoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private scheduleLayout() {
|
||||
if (this.layoutTimer) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.layoutTimer = null;
|
||||
if (!this.isRunningLayout) {
|
||||
this.runLayout(() => this.layoutOwner());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static initWithOwner(owner: WeakRef<View>): UILayoutViewController {
|
||||
const controller = <UILayoutViewController>UILayoutViewController.new();
|
||||
controller.owner = owner;
|
||||
controller._isRunningLayout = 0;
|
||||
|
||||
return controller;
|
||||
}
|
||||
@@ -29,6 +71,11 @@ class UILayoutViewController extends UIViewController {
|
||||
this.extendedLayoutIncludesOpaqueBars = true;
|
||||
}
|
||||
|
||||
public viewSafeAreaInsetsDidChange(): void {
|
||||
super.viewSafeAreaInsetsDidChange();
|
||||
this.scheduleLayout();
|
||||
}
|
||||
|
||||
public viewWillLayoutSubviews(): void {
|
||||
super.viewWillLayoutSubviews();
|
||||
const owner = this.owner?.deref();
|
||||
@@ -38,8 +85,20 @@ class UILayoutViewController extends UIViewController {
|
||||
}
|
||||
|
||||
public viewDidLayoutSubviews(): void {
|
||||
this.startRunningLayout();
|
||||
super.viewDidLayoutSubviews();
|
||||
this.layoutOwner();
|
||||
this.finishRunningLayout();
|
||||
}
|
||||
layoutOwner(force = false) {
|
||||
const owner = this.owner?.deref();
|
||||
if (!force && !!owner.nativeViewProtected?.layer.needsLayout?.()) {
|
||||
// we skip layout if the view is not yet laid out yet
|
||||
// this usually means that viewDidLayoutSubviews will be called again
|
||||
// so doing a layout pass now will layout with the wrong parameters
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner) {
|
||||
if (majorVersion >= 11) {
|
||||
// Handle nested UILayoutViewController safe area application.
|
||||
|
||||
@@ -74,7 +74,6 @@ class UIViewControllerImpl extends UIViewController {
|
||||
|
||||
public isBackstackSkipped: boolean;
|
||||
public isBackstackCleared: boolean;
|
||||
private didFirstLayout: boolean;
|
||||
// this is initialized in initWithOwner since the constructor doesn't run on native classes
|
||||
private _isRunningLayout: number;
|
||||
private get isRunningLayout() {
|
||||
@@ -85,7 +84,7 @@ class UIViewControllerImpl extends UIViewController {
|
||||
}
|
||||
private finishRunningLayout() {
|
||||
this._isRunningLayout--;
|
||||
this.didFirstLayout = true;
|
||||
this.clearScheduledLayout();
|
||||
}
|
||||
private runLayout(cb: () => void) {
|
||||
try {
|
||||
@@ -96,11 +95,31 @@ class UIViewControllerImpl extends UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
layoutTimer: number;
|
||||
|
||||
private clearScheduledLayout() {
|
||||
if (this.layoutTimer) {
|
||||
clearTimeout(this.layoutTimer);
|
||||
this.layoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private scheduleLayout() {
|
||||
if (this.layoutTimer) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.layoutTimer = null;
|
||||
if (!this.isRunningLayout) {
|
||||
this.runLayout(() => this.layoutOwner());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static initWithOwner(owner: WeakRef<Page>): UIViewControllerImpl {
|
||||
const controller = <UIViewControllerImpl>UIViewControllerImpl.new();
|
||||
controller._owner = owner;
|
||||
controller._isRunningLayout = 0;
|
||||
controller.didFirstLayout = false;
|
||||
|
||||
return controller;
|
||||
}
|
||||
@@ -281,19 +300,24 @@ class UIViewControllerImpl extends UIViewController {
|
||||
|
||||
public viewSafeAreaInsetsDidChange(): void {
|
||||
super.viewSafeAreaInsetsDidChange();
|
||||
if (this.isRunningLayout || !this.didFirstLayout) {
|
||||
return;
|
||||
}
|
||||
const owner = this._owner?.deref();
|
||||
if (owner) {
|
||||
this.runLayout(() => IOSHelper.layoutView(this, owner));
|
||||
}
|
||||
this.scheduleLayout();
|
||||
}
|
||||
|
||||
public viewDidLayoutSubviews(): void {
|
||||
this.startRunningLayout();
|
||||
super.viewDidLayoutSubviews();
|
||||
this.layoutOwner();
|
||||
this.finishRunningLayout();
|
||||
}
|
||||
|
||||
layoutOwner(force = false) {
|
||||
const owner = this._owner?.deref();
|
||||
if (!force && !!owner.nativeViewProtected?.layer.needsLayout?.()) {
|
||||
// we skip layout if the view is not yet laid out yet
|
||||
// this usually means that viewDidLayoutSubviews will be called again
|
||||
// so doing a layout pass now will layout with the wrong parameters
|
||||
return;
|
||||
}
|
||||
if (owner) {
|
||||
// layout(owner.actionBar)
|
||||
// layout(owner.content)
|
||||
@@ -345,7 +369,6 @@ class UIViewControllerImpl extends UIViewController {
|
||||
|
||||
IOSHelper.layoutView(this, owner);
|
||||
}
|
||||
this.finishRunningLayout();
|
||||
}
|
||||
|
||||
// Mind implementation for other controllerss
|
||||
|
||||
Reference in New Issue
Block a user