disable recycling on specific button (#4527)

* disable recycling on specific button
add more thorough test for view recycling
fix memory leak with android ActionBar
improve padding reset when view is recycled
improve reset of several controls

* stopping local animations when view is recycled
fix tns-ios version in tests/package.json

* Fix isClickable on android when reusing nativeView
This commit is contained in:
Hristo Hristov
2017-07-11 09:48:08 +03:00
committed by Alexander Vakrilov
parent f092a6ecae
commit 09535627b9
15 changed files with 203 additions and 59 deletions

View File

@@ -133,8 +133,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
public static loadedEvent = "loaded";
public static unloadedEvent = "unloaded";
public recycleNativeView: boolean;
private _recycleNativeView: boolean;
private _iosView: Object;
private _androidView: Object;
private _style: Style;
@@ -204,6 +203,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
public _defaultPaddingRight: number;
public _defaultPaddingBottom: number;
public _defaultPaddingLeft: number;
private _isPaddingRelative: boolean;
constructor() {
super();
@@ -216,6 +216,14 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
return types.getClass(this);
}
get recycleNativeView(): boolean {
return this._recycleNativeView;
}
set recycleNativeView(value: boolean) {
this._recycleNativeView = typeof value === "boolean" ? value : booleanConverter(value);
}
get style(): Style {
return this._style;
}
@@ -630,6 +638,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
if (this._styleScope === view._styleScope) {
view._setStyleScope(null);
}
if (view.isLoaded) {
view.onUnloaded();
}
@@ -662,9 +671,13 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
private resetNativeViewInternal(): void {
const nativeView = this.nativeView;
if (nativeView && this.recycleNativeView && isAndroid) {
if (nativeView && this._recycleNativeView && isAndroid) {
resetNativeView(this);
nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
if (this._isPaddingRelative) {
nativeView.setPaddingRelative(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
} else {
nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
}
this.resetNativeView();
}
if (this._cssState) {
@@ -689,7 +702,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
let nativeView;
if (isAndroid) {
if (this.recycleNativeView) {
if (this._recycleNativeView) {
nativeView = <android.view.View>getNativeView(context, this.typeName);
}
@@ -699,6 +712,10 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
this._androidView = nativeView;
if (nativeView) {
if (this._isPaddingRelative === undefined) {
this._isPaddingRelative = nativeView.isPaddingRelative();
}
let result: android.graphics.Rect = (<any>nativeView).defaultPaddings;
if (result === undefined) {
result = org.nativescript.widgets.ViewHelper.getPadding(nativeView);
@@ -789,7 +806,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
}
const nativeView = this.nativeView;
if (nativeView && this.recycleNativeView && isAndroid) {
if (nativeView && this._recycleNativeView && isAndroid) {
const nativeParent = isAndroid ? (<android.view.View>nativeView).getParent() : (<UIView>nativeView).superview;
if (!nativeParent) {
putNativeView(this._context, this);
@@ -979,7 +996,7 @@ export const idProperty = new Property<ViewBase, string>({ name: "id", valueChan
idProperty.register(ViewBase);
export function booleanConverter(v: string): boolean {
let lowercase = (v + '').toLowerCase();
const lowercase = (v + '').toLowerCase();
if (lowercase === "true") {
return true;
} else if (lowercase === "false") {

View File

@@ -50,15 +50,17 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
private _measuredWidth: number;
private _measuredHeight: number;
private _isLayoutValid: boolean;
private _cssType: string;
private _localAnimations: Set<am.Animation>;
_currentWidthMeasureSpec: number;
_currentHeightMeasureSpec: number;
_setMinWidthNative: (value: Length) => void;
_setMinHeightNative: (value: Length) => void;
private _isLayoutValid: boolean;
private _cssType: string;
public _gestureObservers = {};
observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any): void {
@@ -714,8 +716,35 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
public createAnimation(animation: any): am.Animation {
ensureAnimationModule();
if (!this._localAnimations) {
this._localAnimations = new Set();
}
animation.target = this;
return new animationModule.Animation([animation]);
const anim = new animationModule.Animation([animation]);
this._localAnimations.add(anim);
return anim;
}
public _removeAnimation(animation: am.Animation): boolean {
const localAnimations = this._localAnimations;
if (localAnimations && localAnimations.has(animation)) {
localAnimations.delete(animation);
if (animation.isPlaying) {
animation.cancel();
}
return true;
}
return false;
}
public resetNativeView(): void {
if (this._localAnimations) {
this._localAnimations.forEach(a => this._removeAnimation(a));
}
super.resetNativeView();
}
public toString(): string {

View File

@@ -70,6 +70,7 @@ function initializeTouchListener(): void {
}
export class View extends ViewCommon {
private _isClickable: boolean;
private touchListenerIsSet: boolean;
private touchListener: android.view.View.OnTouchListener;
@@ -94,6 +95,7 @@ export class View extends ViewCommon {
if (this.touchListenerIsSet) {
this.nativeView.setOnTouchListener(null);
this.touchListenerIsSet = false;
this.nativeView.setClickable(this._isClickable);
}
this._cancelAllAnimations();
@@ -104,6 +106,11 @@ export class View extends ViewCommon {
return this._gestureObservers && Object.keys(this._gestureObservers).length > 0
}
public initNativeView(): void {
super.initNativeView();
this._isClickable = this.nativeView.isClickable();
}
private setOnTouchListener() {
if (this.nativeView && this.hasGestureObservers()) {
this.touchListenerIsSet = true;

View File

@@ -558,6 +558,10 @@ export abstract class View extends ViewBase implements ApplyXmlAttributes {
* @private
*/
_redrawNativeBackground(value: any): void;
/**
* @private
*/
_removeAnimation(animation: Animation): boolean
//@endprivate
/**