mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(core): reusable views (#9163)
This commit is contained in:
committed by
Nathan Walker
parent
e9e4934faf
commit
6cc130fa6f
13
packages/core/ui/core/view-base/index.d.ts
vendored
13
packages/core/ui/core/view-base/index.d.ts
vendored
@@ -236,6 +236,12 @@ export abstract class ViewBase extends Observable {
|
||||
public nativeView: any;
|
||||
public bindingContext: any;
|
||||
|
||||
/**
|
||||
* Gets or sets if the view is reusable.
|
||||
* Reusable views are not automatically destroyed when removed from the View tree.
|
||||
*/
|
||||
public reusable: boolean;
|
||||
|
||||
/**
|
||||
* Gets the name of the constructor function for this instance. E.g. for a Button class this will return "Button".
|
||||
*/
|
||||
@@ -365,6 +371,13 @@ export abstract class ViewBase extends Observable {
|
||||
*/
|
||||
_tearDownUI(force?: boolean): void;
|
||||
|
||||
/**
|
||||
* Tears down the UI of a reusable node by making it no longer reusable.
|
||||
* @see _tearDownUI
|
||||
* @param forceDestroyChildren Force destroy the children (even if they are reusable)
|
||||
*/
|
||||
destroyNode(forceDestroyChildren?: boolean): void;
|
||||
|
||||
/**
|
||||
* Creates a native view.
|
||||
* Returns either android.view.View or UIView.
|
||||
|
||||
@@ -307,6 +307,8 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
public _moduleName: string;
|
||||
|
||||
public reusable: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._domId = viewIdCounter++;
|
||||
@@ -767,6 +769,14 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
@profile
|
||||
public _setupUI(context: any, atIndex?: number, parentIsLoaded?: boolean): void {
|
||||
if (this._context === context) {
|
||||
// this check is unnecessary as this function should never be called when this._context === context as it means the view was somehow detached,
|
||||
// which is only possible by setting reusable = true. Adding it either way for feature flag safety
|
||||
if (this.reusable) {
|
||||
if (this.parent && !this._isAddedToNativeVisualTree) {
|
||||
const nativeIndex = this.parent._childIndexToNativeChildIndex(atIndex);
|
||||
this._isAddedToNativeVisualTree = this.parent._addViewToNativeVisualTree(this, nativeIndex);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (this._context) {
|
||||
this._tearDownUI(true);
|
||||
@@ -789,35 +799,39 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
|
||||
if (global.isAndroid) {
|
||||
this._androidView = nativeView;
|
||||
if (nativeView) {
|
||||
if (this._isPaddingRelative === undefined) {
|
||||
this._isPaddingRelative = nativeView.isPaddingRelative();
|
||||
}
|
||||
// this check is also unecessary as this code should never be reached with _androidView != null unless reusable = true
|
||||
// also adding this check for feature flag safety
|
||||
if (this._androidView !== nativeView || !this.reusable) {
|
||||
this._androidView = nativeView;
|
||||
if (nativeView) {
|
||||
if (this._isPaddingRelative === undefined) {
|
||||
this._isPaddingRelative = nativeView.isPaddingRelative();
|
||||
}
|
||||
|
||||
let result: any /* android.graphics.Rect */ = (<any>nativeView).defaultPaddings;
|
||||
if (result === undefined) {
|
||||
result = org.nativescript.widgets.ViewHelper.getPadding(nativeView);
|
||||
(<any>nativeView).defaultPaddings = result;
|
||||
}
|
||||
let result: any /* android.graphics.Rect */ = (<any>nativeView).defaultPaddings;
|
||||
if (result === undefined) {
|
||||
result = org.nativescript.widgets.ViewHelper.getPadding(nativeView);
|
||||
(<any>nativeView).defaultPaddings = result;
|
||||
}
|
||||
|
||||
this._defaultPaddingTop = result.top;
|
||||
this._defaultPaddingRight = result.right;
|
||||
this._defaultPaddingBottom = result.bottom;
|
||||
this._defaultPaddingLeft = result.left;
|
||||
this._defaultPaddingTop = result.top;
|
||||
this._defaultPaddingRight = result.right;
|
||||
this._defaultPaddingBottom = result.bottom;
|
||||
this._defaultPaddingLeft = result.left;
|
||||
|
||||
const style = this.style;
|
||||
if (!paddingTopProperty.isSet(style)) {
|
||||
this.effectivePaddingTop = this._defaultPaddingTop;
|
||||
}
|
||||
if (!paddingRightProperty.isSet(style)) {
|
||||
this.effectivePaddingRight = this._defaultPaddingRight;
|
||||
}
|
||||
if (!paddingBottomProperty.isSet(style)) {
|
||||
this.effectivePaddingBottom = this._defaultPaddingBottom;
|
||||
}
|
||||
if (!paddingLeftProperty.isSet(style)) {
|
||||
this.effectivePaddingLeft = this._defaultPaddingLeft;
|
||||
const style = this.style;
|
||||
if (!paddingTopProperty.isSet(style)) {
|
||||
this.effectivePaddingTop = this._defaultPaddingTop;
|
||||
}
|
||||
if (!paddingRightProperty.isSet(style)) {
|
||||
this.effectivePaddingRight = this._defaultPaddingRight;
|
||||
}
|
||||
if (!paddingBottomProperty.isSet(style)) {
|
||||
this.effectivePaddingBottom = this._defaultPaddingBottom;
|
||||
}
|
||||
if (!paddingLeftProperty.isSet(style)) {
|
||||
this.effectivePaddingLeft = this._defaultPaddingLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -858,20 +872,28 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
}
|
||||
|
||||
public destroyNode(forceDestroyChildren?: boolean): void {
|
||||
this.reusable = false;
|
||||
this._tearDownUI(forceDestroyChildren);
|
||||
}
|
||||
|
||||
@profile
|
||||
public _tearDownUI(force?: boolean): void {
|
||||
// No context means we are already teared down.
|
||||
if (!this._context) {
|
||||
return;
|
||||
}
|
||||
const preserveNativeView = this.reusable && !force;
|
||||
|
||||
this.resetNativeViewInternal();
|
||||
|
||||
this.eachChild((child) => {
|
||||
child._tearDownUI(force);
|
||||
if (!preserveNativeView) {
|
||||
this.eachChild((child) => {
|
||||
child._tearDownUI(force);
|
||||
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (this.parent) {
|
||||
this.parent._removeViewFromNativeVisualTree(this);
|
||||
@@ -896,19 +918,21 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
// }
|
||||
// }
|
||||
|
||||
this.disposeNativeView();
|
||||
if (!preserveNativeView) {
|
||||
this.disposeNativeView();
|
||||
|
||||
this._suspendNativeUpdates(SuspendType.UISetup);
|
||||
this._suspendNativeUpdates(SuspendType.UISetup);
|
||||
|
||||
if (global.isAndroid) {
|
||||
this.setNativeView(null);
|
||||
this._androidView = null;
|
||||
if (global.isAndroid) {
|
||||
this.setNativeView(null);
|
||||
this._androidView = null;
|
||||
}
|
||||
|
||||
// this._iosView = null;
|
||||
|
||||
this._context = null;
|
||||
}
|
||||
|
||||
// this._iosView = null;
|
||||
|
||||
this._context = null;
|
||||
|
||||
if (this.domNode) {
|
||||
this.domNode.dispose();
|
||||
this.domNode = undefined;
|
||||
@@ -1099,6 +1123,7 @@ ViewBase.prototype._defaultPaddingBottom = 0;
|
||||
ViewBase.prototype._defaultPaddingLeft = 0;
|
||||
ViewBase.prototype._isViewBase = true;
|
||||
ViewBase.prototype.recycleNativeView = 'never';
|
||||
ViewBase.prototype.reusable = false;
|
||||
|
||||
ViewBase.prototype._suspendNativeUpdatesCount = SuspendType.Loaded | SuspendType.NativeView | SuspendType.UISetup;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user