mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-14 10:01:08 +08:00
fix(ios): proper disposal and recreation of iOS native views (#9879)
This commit is contained in:

committed by
Nathan Walker

parent
b7e6128576
commit
f548fdc735
@ -1,7 +1,7 @@
|
||||
import * as helper from '../../ui-helper';
|
||||
import * as btnCounter from './pages/button-counter';
|
||||
import * as TKUnit from '../../tk-unit';
|
||||
import { isIOS, isAndroid } from '@nativescript/core';
|
||||
import { isIOS } from '@nativescript/core';
|
||||
|
||||
// Integration tests that asser sertain runtime behavior, lifecycle events atc.
|
||||
|
||||
@ -163,7 +163,7 @@ export function test_css_sets_properties() {
|
||||
page.content = stack;
|
||||
|
||||
// TODO: The check counts here should be the same as the counts before removing from the page.
|
||||
const expectedNativeSettersAfterReaddedToPage = isAndroid ? [2, 4, 4, 4] : expectedChangesAfterResettingClasses;
|
||||
const expectedNativeSettersAfterReaddedToPage = [2, 4, 4, 4];
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
TKUnit.assertEqual(buttons[i].colorSetNativeCount, expectedNativeSettersAfterReaddedToPage[i], `Expected ${buttons[i].id} native set to not be called when added to page.`);
|
||||
TKUnit.assertEqual(buttons[i].colorPropertyChangeCount, expectedChangesAfterResettingClasses[i], `Expected ${buttons[i].id} change notifications for css properties to not occur when added to page.`);
|
||||
|
@ -69,5 +69,5 @@ export interface AnimationDefinitionInternal extends AnimationDefinition {
|
||||
export interface IOSView extends View {
|
||||
_suspendPresentationLayerUpdates();
|
||||
_resumePresentationLayerUpdates();
|
||||
_isPresentationLayerUpdateSuspeneded();
|
||||
_isPresentationLayerUpdateSuspended();
|
||||
}
|
||||
|
@ -909,6 +909,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
public destroyNode(forceDestroyChildren?: boolean): void {
|
||||
this.reusable = false;
|
||||
this.callUnloaded();
|
||||
this._tearDownUI(forceDestroyChildren);
|
||||
}
|
||||
|
||||
@ -958,12 +959,9 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
this._suspendNativeUpdates(SuspendType.UISetup);
|
||||
|
||||
if (global.isAndroid) {
|
||||
this.setNativeView(null);
|
||||
this._androidView = null;
|
||||
}
|
||||
|
||||
// this._iosView = null;
|
||||
this.setNativeView(null);
|
||||
this._androidView = null;
|
||||
this._iosView = null;
|
||||
|
||||
this._context = null;
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
*/
|
||||
private _modalAnimatedOptions: Array<boolean>;
|
||||
private _isLaidOut = false;
|
||||
private _hasTransfrom = false;
|
||||
private _hasTransform = false;
|
||||
private _hasPendingTransform = false;
|
||||
private _privateFlags: number = PFLAG_LAYOUT_REQUIRED | PFLAG_FORCE_LAYOUT;
|
||||
private _cachedFrame: CGRect;
|
||||
private _suspendCATransaction = false;
|
||||
@ -63,6 +64,15 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
this.once(View.loadedEvent, () => setupAccessibleView(this));
|
||||
}
|
||||
|
||||
disposeNativeView() {
|
||||
super.disposeNativeView();
|
||||
|
||||
this._cachedFrame = null;
|
||||
this._isLaidOut = false;
|
||||
this._hasTransform = false;
|
||||
this._hasPendingTransform = false;
|
||||
}
|
||||
|
||||
public requestLayout(): void {
|
||||
super.requestLayout();
|
||||
this._privateFlags |= PFLAG_FORCE_LAYOUT;
|
||||
@ -119,6 +129,10 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
}
|
||||
|
||||
this.updateBackground(sizeChanged);
|
||||
if (this._hasPendingTransform) {
|
||||
this.updateNativeTransform();
|
||||
this._hasPendingTransform = false;
|
||||
}
|
||||
this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
|
||||
}
|
||||
|
||||
@ -175,7 +189,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
this._cachedFrame = frame;
|
||||
let adjustedFrame = null;
|
||||
let transform = null;
|
||||
if (this._hasTransfrom) {
|
||||
if (this._hasTransform) {
|
||||
// Always set identity transform before setting frame;
|
||||
transform = nativeView.layer.transform;
|
||||
nativeView.layer.transform = CATransform3DIdentity;
|
||||
@ -189,7 +203,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
nativeView.frame = adjustedFrame;
|
||||
}
|
||||
|
||||
if (this._hasTransfrom) {
|
||||
if (this._hasTransform) {
|
||||
// re-apply the transform after the frame is adjusted
|
||||
nativeView.layer.transform = transform;
|
||||
}
|
||||
@ -363,6 +377,11 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
}
|
||||
|
||||
public updateNativeTransform() {
|
||||
if (!this.isLayoutValid) {
|
||||
this._hasPendingTransform = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const scaleX = this.scaleX || 1e-6;
|
||||
const scaleY = this.scaleY || 1e-6;
|
||||
const perspective = this.perspective || 300;
|
||||
@ -378,12 +397,12 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
transform = iOSNativeHelper.applyRotateTransform(transform, this.rotateX, this.rotateY, this.rotate);
|
||||
transform = CATransform3DScale(transform, scaleX, scaleY, 1);
|
||||
if (!CATransform3DEqualToTransform(this.nativeViewProtected.layer.transform, transform)) {
|
||||
const updateSuspended = this._isPresentationLayerUpdateSuspeneded();
|
||||
const updateSuspended = this._isPresentationLayerUpdateSuspended();
|
||||
if (!updateSuspended) {
|
||||
CATransaction.begin();
|
||||
}
|
||||
this.nativeViewProtected.layer.transform = transform;
|
||||
this._hasTransfrom = this.nativeViewProtected && !CATransform3DEqualToTransform(this.nativeViewProtected.transform3D, CATransform3DIdentity);
|
||||
this._hasTransform = this.nativeViewProtected && !CATransform3DEqualToTransform(this.nativeViewProtected.transform3D, CATransform3DIdentity);
|
||||
if (!updateSuspended) {
|
||||
CATransaction.commit();
|
||||
}
|
||||
@ -409,7 +428,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
this._suspendCATransaction = false;
|
||||
}
|
||||
|
||||
public _isPresentationLayerUpdateSuspeneded(): boolean {
|
||||
public _isPresentationLayerUpdateSuspended(): boolean {
|
||||
return this._suspendCATransaction || this._suspendNativeUpdatesCount > 0;
|
||||
}
|
||||
|
||||
@ -689,7 +708,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
}
|
||||
[opacityProperty.setNative](value: number) {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const updateSuspended = this._isPresentationLayerUpdateSuspeneded();
|
||||
const updateSuspended = this._isPresentationLayerUpdateSuspended();
|
||||
if (!updateSuspended) {
|
||||
CATransaction.begin();
|
||||
}
|
||||
@ -845,7 +864,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
}
|
||||
|
||||
_redrawNativeBackground(value: UIColor | Background): void {
|
||||
const updateSuspended = this._isPresentationLayerUpdateSuspeneded();
|
||||
const updateSuspended = this._isPresentationLayerUpdateSuspended();
|
||||
if (!updateSuspended) {
|
||||
CATransaction.begin();
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ class UILayoutViewController extends UIViewController {
|
||||
|
||||
IOSHelper.updateAutoAdjustScrollInsets(this, owner);
|
||||
|
||||
if (!owner.parent) {
|
||||
if (!owner.isLoaded && !owner.parent) {
|
||||
owner.callLoaded();
|
||||
}
|
||||
}
|
||||
@ -109,7 +109,7 @@ class UILayoutViewController extends UIViewController {
|
||||
public viewDidDisappear(animated: boolean): void {
|
||||
super.viewDidDisappear(animated);
|
||||
const owner = this.owner.get();
|
||||
if (owner && !owner.parent) {
|
||||
if (owner && owner.isLoaded && !owner.parent) {
|
||||
owner.callUnloaded();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user