Improve background setter in iOS (#3582)

CoercableProperty now inherits from Property
VS Code typescript sdk removed
ViewBase will no longer clear native view if recycleNativeView is false
This commit is contained in:
Hristo Hristov
2017-02-06 11:49:54 +02:00
committed by GitHub
parent 4440569522
commit f539dd5f95
12 changed files with 476 additions and 512 deletions

View File

@@ -38,7 +38,7 @@ const enum ValueSource {
Local = 3
}
export class Property<T extends ViewBase, U> implements PropertyDescriptor, definitions.Property<T, U> {
export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<U>, definitions.Property<T, U> {
private registered: boolean;
public readonly name: string;
@@ -174,40 +174,20 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor, defi
}
}
export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescriptor, definitions.CoercibleProperty<T, U> {
private registered: boolean;
private readonly name: string;
public readonly key: symbol;
public readonly native: symbol;
public readonly defaultValueKey: symbol;
public readonly defaultValue: U;
public readonly nativeValueChange: (owner: T, value: U) => void;
public readonly get: () => U;
public readonly set: (value: U) => void;
public readonly enumerable: boolean = true;
public readonly configurable: boolean = true;
export class CoercibleProperty<T extends ViewBase, U> extends Property<T, U> implements definitions.CoercibleProperty<T, U> {
public readonly coerce: (target: T) => void;
constructor(options: definitions.CoerciblePropertyOptions<T, U>) {
super(options);
const name = options.name;
this.name = name;
const key = Symbol(name + ":propertyKey");
this.key = key;
const native: symbol = Symbol(name + ":nativeKey");
this.native = native;
const defaultValueKey = Symbol(name + ":nativeDefaultValue");
this.defaultValueKey = defaultValueKey;
const key = this.key;
const native: symbol = this.native;
const defaultValueKey = this.defaultValueKey;
const defaultValue: U = this.defaultValue;
const coerceKey = Symbol(name + ":coerceKey");
const defaultValue: U = options.defaultValue;
this.defaultValue = defaultValue;
const eventName = name + "Change";
const affectsLayout: boolean = options.affectsLayout;
const equalityComparer = options.equalityComparer;
@@ -218,8 +198,8 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
this.coerce = function (target: T): void {
const originalValue: U = coerceKey in target ? target[coerceKey] : defaultValue;
// need that to make coercing but also fire change events
this.set.call(target, originalValue);
};
target[name] = originalValue;
}
this.set = function (this: T, value: U): void {
const reset = value === unsetValue;
@@ -283,46 +263,7 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
this.requestLayout();
}
}
};
this.get = function (): U {
return key in this ? this[key] : defaultValue;
};
this.nativeValueChange = function (owner: T, value: U): void {
const currentValue = key in owner ? owner[key] : defaultValue;
const changed = equalityComparer ? !equalityComparer(currentValue, value) : currentValue !== value;
if (changed) {
owner[key] = value;
owner[coerceKey] = value;
if (valueChanged) {
valueChanged(owner, currentValue, value);
}
if (owner.hasListeners(eventName)) {
owner.notify({
eventName: eventName,
propertyName: name,
object: owner,
value: value
});
}
if (affectsLayout) {
owner.requestLayout();
}
}
};
symbolPropertyMap[key] = this;
}
public register(cls: { prototype: T }): void {
if (this.registered) {
throw new Error(`Property ${this.name} already registered.`);
}
this.registered = true;
Object.defineProperty(cls.prototype, this.name, this);
}
}
@@ -832,7 +773,7 @@ function inheritableCssPropertyValuesOn(style: Style): Array<{ property: Inherit
return array;
}
export function applyNativeSetters(view: ViewBase): void {
export function initNativeView(view: ViewBase): void {
let symbols = (<any>Object).getOwnPropertySymbols(view);
for (let symbol of symbols) {
const property: Property<any, any> = symbolPropertyMap[symbol];
@@ -873,6 +814,44 @@ export function applyNativeSetters(view: ViewBase): void {
}
}
export function resetNativeView(view: ViewBase): void {
let symbols = (<any>Object).getOwnPropertySymbols(view);
for (let symbol of symbols) {
const property: Property<any, any> = symbolPropertyMap[symbol];
if (!property) {
continue;
}
const native = property.native;
if (native in view) {
view[native] = view[property.defaultValueKey];
delete view[property.defaultValueKey];
}
// This will not call propertyChange!!!
delete view[property.key];
}
const style = view.style;
symbols = (<any>Object).getOwnPropertySymbols(style);
for (let symbol of symbols) {
const property: CssProperty<any, any> = cssSymbolPropertyMap[symbol];
if (!property) {
continue;
}
const native = property.native;
if (native in view) {
view[native] = style[property.defaultValueKey];
delete style[property.defaultValueKey];
}
// This will not call propertyChange!!!
delete style[property.key];
}
}
export function clearInheritedProperties(view: ViewBase): void {
for (let prop of inheritableProperties) {
const sourceKey = prop.sourceKey;
@@ -902,26 +881,6 @@ export function resetCSSProperties(style: Style): void {
}
}
export function resetStyleProperties(style: Style): void {
let symbols = (<any>Object).getOwnPropertySymbols(style);
const view = style.view;
for (let symbol of symbols) {
const property: CssProperty<any, any> = symbolPropertyMap[symbol];
if (!property) {
continue;
}
const native = property.native;
if (native in view) {
view[native] = style[property.defaultValueKey];
delete style[property.defaultValueKey];
}
// This will not call propertyChange!!!
delete style[property.key];
}
}
export function propagateInheritedProperties(view: ViewBase): void {
const inheritablePropertyValues = inheritablePropertyValuesOn(view);
const inheritableCssPropertyValues = inheritableCssPropertyValuesOn(view.style);
@@ -966,4 +925,4 @@ export function makeParser<T>(isValid: (value: any) => boolean): (value: any) =>
throw new Error("Invalid value: " + value);
}
};
}
}

View File

@@ -1,6 +1,6 @@
import { ViewBase as ViewBaseDefinition } from "ui/core/view-base";
import { Observable, EventData, PropertyChangeData } from "data/observable";
import { Property, InheritedProperty, Style, clearInheritedProperties, propagateInheritedProperties, resetCSSProperties, applyNativeSetters, resetStyleProperties } from "./properties";
import { Property, InheritedProperty, Style, clearInheritedProperties, propagateInheritedProperties, resetCSSProperties, initNativeView, resetNativeView } from "./properties";
import { Binding, BindingOptions } from "ui/core/bindable";
import { isIOS, isAndroid } from "platform";
import { fromString as gestureFromString } from "ui/gestures";
@@ -15,7 +15,7 @@ import * as types from "utils/types";
import * as ssm from "ui/styling/style-scope";
let styleScopeModule: typeof ssm;
function ensureStyleScopeModule() {
if (!styleScopeModule){
if (!styleScopeModule) {
styleScopeModule = require("ui/styling/style-scope");
}
}
@@ -107,6 +107,8 @@ export function eachDescendant(view: ViewBaseDefinition, callback: (child: ViewB
let viewIdCounter = 0;
export class ViewBase extends Observable implements ViewBaseDefinition {
public recycleNativeView: boolean;
private _style: Style;
private _isLoaded: boolean;
private _registeredAnimations: Array<KeyframeAnimation>;
@@ -505,7 +507,9 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
}
public _resetNativeView(): void {
//
if (this.nativeView && this.recycleNativeView) {
resetNativeView(this);
}
}
public _setupUI(context: android.content.Context, atIndex?: number) {
@@ -533,7 +537,7 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
}
if (this.nativeView) {
applyNativeSetters(this);
initNativeView(this);
}
this.eachChild((child) => {
@@ -552,11 +556,6 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
return true;
});
if (this.nativeView) {
// TODO: rename and implement this as resetNativeSetters
resetStyleProperties(this.style);
}
if (this.parent) {
this.parent._removeViewFromNativeVisualTree(this);
}