up to segmented-bar.ios

This commit is contained in:
Hristo Hristov
2016-12-08 18:20:25 +02:00
parent 007b78325c
commit befb494a50
43 changed files with 847 additions and 1044 deletions

View File

@@ -27,7 +27,7 @@ export interface PropertyOptions<T, U> {
}
export interface CoerciblePropertyOptions<T, U> extends PropertyOptions<T, U> {
coerceValue(T, U): U
readonly coerceValue: (T, U) => U;
}
export interface ShorthandPropertyOptions {
@@ -95,6 +95,10 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor {
this[key] = unboxedValue;
}
if (this.nativeView) {
this[native] = unboxedValue;
}
if (valueChanged) {
valueChanged(this, currentValue, unboxedValue);
}
@@ -108,10 +112,6 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor {
});
}
if (this.nativeView) {
this[native] = unboxedValue;
}
if (affectsLayout) {
this.requestLayout();
}
@@ -201,6 +201,10 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
this[key] = unboxedValue;
}
if (this.nativeView) {
this[native] = unboxedValue;
}
if (valueChanged) {
valueChanged(this, currentValue, unboxedValue);
}
@@ -214,10 +218,6 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
});
}
if (this.nativeView) {
this[native] = unboxedValue;
}
if (affectsLayout) {
this.requestLayout();
}
@@ -378,6 +378,15 @@ export class CssProperty<T extends Style, U> {
this[key] = value;
}
let view = this.view;
if (view.nativeView) {
view[native] = value;
if (dependentPropertyNativeKey) {
// Call the native setter for dependent property.
view[dependentPropertyNativeKey] = this[dependentPropertyKey];
}
}
if (valueChanged) {
valueChanged(this, currentValue, value);
}
@@ -391,15 +400,6 @@ export class CssProperty<T extends Style, U> {
});
}
let view = this.view;
if (view.nativeView) {
view[native] = value;
if (dependentPropertyNativeKey) {
// Call the native setter for dependent property.
view[dependentPropertyNativeKey] = this[dependentPropertyKey];
}
}
if (affectsLayout) {
view.requestLayout();
}
@@ -435,6 +435,15 @@ export class CssProperty<T extends Style, U> {
this[key] = value;
}
let view = this.view;
if (view.nativeView) {
view[native] = value;
if (dependentPropertyNativeKey) {
// Call the native setter for dependent property.
view[dependentPropertyNativeKey] = this[dependentPropertyKey];
}
}
if (valueChanged) {
valueChanged(this, currentValue, value);
}
@@ -448,15 +457,6 @@ export class CssProperty<T extends Style, U> {
});
}
let view = this.view;
if (view.nativeView) {
view[native] = value;
if (dependentPropertyNativeKey) {
// Call the native setter for dependent property.
view[dependentPropertyNativeKey] = this[dependentPropertyKey];
}
}
if (affectsLayout) {
view.requestLayout();
}
@@ -568,6 +568,15 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
this[key] = newValue;
}
let nativeView = view.nativeView;
if (nativeView) {
view[native] = value;
if (dependentPropertyNativeKey) {
// Call the native setter for dependent property.
view[dependentPropertyNativeKey] = this[dependentPropertyKey];
}
}
if (valueChanged) {
valueChanged(this, currentValue, newValue);
}
@@ -581,15 +590,6 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
});
}
let nativeView = view.nativeView;
if (nativeView) {
view[native] = value;
if (dependentPropertyNativeKey) {
// Call the native setter for dependent property.
view[dependentPropertyNativeKey] = this[dependentPropertyKey];
}
}
if (affectsLayout) {
view.requestLayout();
}
@@ -752,7 +752,7 @@ function inheritableCssPropertiesOn(style: Object): Array<InheritedCssProperty<a
}
export function applyNativeSetters(view: ViewBase): void {
let symbols = Object.getOwnPropertySymbols(view);
let symbols = (<any>Object).getOwnPropertySymbols(view);
for (let symbol of symbols) {
let property: Property<any, any> = symbolPropertyMap[symbol];
if (!property) {
@@ -767,7 +767,7 @@ export function applyNativeSetters(view: ViewBase): void {
}
let style = view.style;
symbols = Object.getOwnPropertySymbols(style);
symbols = (<any>Object).getOwnPropertySymbols(style);
for (let symbol of symbols) {
let property: CssProperty<any, any> = cssSymbolPropertyMap[symbol];
if (!property) {

View File

@@ -1,11 +1,15 @@
import { ViewBase as ViewBaseDefinition } from "ui/core/view-base";
import { Observable, EventData } from "data/observable";
import { Property, InheritedProperty, CssProperty, Style } from "./properties";
import { Property, InheritedProperty, CssProperty, Style, clearInheritedProperties, propagateInheritedProperties } from "./properties";
import { Binding, BindingOptions, Bindable } from "ui/core/bindable";
import { isIOS } from "platform";
import { fromString as gestureFromString } from "ui/gestures";
import { CssState, StyleScope, applyInlineSyle } from "ui/styling/style-scope";
import { KeyframeAnimation } from "ui/animation/keyframe-animation";
export { Observable, EventData, Binding, BindingOptions, Bindable, isIOS, gestureFromString };
import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, notifyEvent as traceNotifyEvent } from "trace";
export { KeyframeAnimation, Observable, EventData, Binding, BindingOptions, Bindable, isIOS, gestureFromString, traceEnabled, traceWrite, traceCategories, traceNotifyEvent };
export * from "./properties";
let defaultBindingSource = {};
@@ -46,12 +50,19 @@ export function isEventOrGesture(name: string, view: ViewBaseDefinition): boolea
export class ViewBase extends Observable implements ViewBaseDefinition {
private _updatingJSPropertiesDict = {};
private _style: Style;
private _isLoaded: boolean;
private _registeredAnimations: Array<KeyframeAnimation>;
private _visualState: string;
public bindingContext: any;
public nativeView: any;
public parent: ViewBase;
public isCollapsed;
public id: string;
public className: string;
public _cssState: CssState;
constructor() {
super();
this._style = new Style(this);
@@ -69,6 +80,200 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
return undefined;
}
get isLoaded(): boolean {
return this._isLoaded;
}
get page(): ViewBaseDefinition {
if (this.parent) {
return this.parent.page;
}
return null;
}
protected onLoaded() {
this._isLoaded = true;
this._loadEachChildView();
this._applyStyleFromScope();
this._emit("loaded");
}
get _childrenCount(): number {
return 0;
}
public _loadEachChildView() {
if (this._childrenCount > 0) {
this.eachChild((child) => {
child.onLoaded();
return true;
});
}
}
protected onUnloaded() {
this._setCssState(null);
this._unloadEachChildView();
this._isLoaded = false;
this._emit("unloaded");
}
private _unloadEachChildView() {
if (this._childrenCount > 0) {
this.eachChild((child) => {
if (child.isLoaded) {
child.onUnloaded();
}
return true;
});
}
}
private _applyStyleFromScope() {
let rootPage = this.page;
if (!rootPage || !rootPage.isLoaded) {
return;
}
let scope: StyleScope = (<any>rootPage)._getStyleScope();
scope.applySelectors(this);
}
// TODO: Make sure the state is set to null and this is called on unloaded to clean up change listeners...
_setCssState(next: CssState): void {
const previous = this._cssState;
this._cssState = next;
if (!this._invalidateCssHandler) {
this._invalidateCssHandler = () => {
if (this._invalidateCssHandlerSuspended) {
return;
}
this.applyCssState();
};
}
try {
this._invalidateCssHandlerSuspended = true;
if (next) {
next.changeMap.forEach((changes, view) => {
if (changes.attributes) {
changes.attributes.forEach(attribute => {
view.addEventListener(attribute + "Change", this._invalidateCssHandler)
});
}
if (changes.pseudoClasses) {
changes.pseudoClasses.forEach(pseudoClass => {
let eventName = ":" + pseudoClass;
view.addEventListener(":" + pseudoClass, this._invalidateCssHandler);
if (view[eventName]) {
view[eventName](+1);
}
});
}
});
}
if (previous) {
previous.changeMap.forEach((changes, view) => {
if (changes.attributes) {
changes.attributes.forEach(attribute => {
view.removeEventListener("onPropertyChanged:" + attribute, this._invalidateCssHandler)
});
}
if (changes.pseudoClasses) {
changes.pseudoClasses.forEach(pseudoClass => {
let eventName = ":" + pseudoClass;
view.removeEventListener(eventName, this._invalidateCssHandler)
if (view[eventName]) {
view[eventName](-1);
}
});
}
});
}
} finally {
this._invalidateCssHandlerSuspended = false;
}
this.applyCssState();
}
private notifyPseudoClassChanged(pseudoClass: string): void {
this.notify({ eventName: ":" + pseudoClass, object: this });
}
/**
* Notify that some attributes or pseudo classes that may affect the current CssState had changed.
*/
private _invalidateCssHandler;
private _invalidateCssHandlerSuspended: boolean;
private applyCssState(): void {
if (!this._cssState) {
return;
}
// this.style._beginUpdate();
this._cssState.apply();
// this.style._endUpdate();
}
private pseudoClassAliases = {
'highlighted': [
'active',
'pressed'
]
};
public cssClasses: Set<string> = new Set();
public cssPseudoClasses: Set<string> = new Set();
private getAllAliasedStates(name: string): Array<string> {
let allStates = [];
allStates.push(name);
if (name in this.pseudoClassAliases) {
for (let i = 0; i < this.pseudoClassAliases[name].length; i++) {
allStates.push(this.pseudoClassAliases[name][i]);
}
}
return allStates;
}
public addPseudoClass(name: string): void {
let allStates = this.getAllAliasedStates(name);
for (let i = 0; i < allStates.length; i++) {
if (!this.cssPseudoClasses.has(allStates[i])) {
this.cssPseudoClasses.add(allStates[i]);
this.notifyPseudoClassChanged(allStates[i]);
}
}
}
public deletePseudoClass(name: string): void {
let allStates = this.getAllAliasedStates(name);
for (let i = 0; i < allStates.length; i++) {
if (this.cssPseudoClasses.has(allStates[i])) {
this.cssPseudoClasses.delete(allStates[i]);
this.notifyPseudoClassChanged(allStates[i]);
}
}
}
private _applyInlineStyle(inlineStyle) {
if (typeof inlineStyle === "string") {
try {
// this.style._beginUpdate();
applyInlineSyle(this, inlineStyle);
} finally {
// this.style._endUpdate();
}
}
}
private bindings = new Map<string, Binding>();
public bind(options: BindingOptions, source: Object = defaultBindingSource): void {
let binding: Binding = this.bindings.get(options.targetProperty);
@@ -126,6 +331,125 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
public eachChild(callback: (child: ViewBase) => boolean) {
//
}
public _addView(view: ViewBase, atIndex?: number) {
if (traceEnabled) {
traceWrite(`${this}._addView(${view}, ${atIndex})`, traceCategories.ViewHierarchy);
}
if (!view) {
throw new Error("Expecting a valid View instance.");
}
if (!(view instanceof ViewBase)) {
throw new Error(view + " is not a valid View instance.");
}
if (view.parent) {
throw new Error("View already has a parent. View: " + view + " Parent: " + view.parent);
}
view.parent = this;
this._addViewCore(view, atIndex);
view._parentChanged(null);
}
protected _addViewCore(view: ViewBase, atIndex?: number) {
// TODO: Discuss this.
if (this._isLoaded) {
view.onLoaded();
}
propagateInheritedProperties(this);
}
/**
* Core logic for removing a child view from this instance. Used by the framework to handle lifecycle events more centralized. Do not outside the UI Stack implementation.
*/
public _removeView(view: ViewBase) {
if (traceEnabled) {
traceWrite(`${this}._removeView(${view})`, traceCategories.ViewHierarchy);
}
if (view.parent !== this) {
throw new Error("View not added to this instance. View: " + view + " CurrentParent: " + view.parent + " ExpectedParent: " + this);
}
this._removeViewCore(view);
view.parent = undefined;
view._parentChanged(this);
}
/**
* Method is intended to be overridden by inheritors and used as "protected"
*/
public _removeViewCore(view: ViewBase) {
// TODO: Discuss this.
if (view.isLoaded) {
view.onUnloaded();
}
// view.unsetInheritedProperties();
}
public _goToVisualState(state: string) {
if (traceEnabled) {
traceWrite(this + " going to state: " + state, traceCategories.Style);
}
if (state === this._visualState) {
return;
}
this.deletePseudoClass(this._visualState);
this._visualState = state;
this.addPseudoClass(state);
}
public _applyXmlAttribute(attribute, value): boolean {
if (attribute === "style") {
this._applyInlineStyle(value);
return true;
}
return false;
}
public setInlineStyle(style: string): void {
if (typeof style !== "string") {
throw new Error("Parameter should be valid CSS string!");
}
this._applyInlineStyle(style);
}
public _parentChanged(oldParent: ViewBase): void {
//Overridden
if (oldParent) {
// Move these method in property class.
clearInheritedProperties(this);
}
}
public _registerAnimation(animation: KeyframeAnimation) {
if (this._registeredAnimations === undefined) {
this._registeredAnimations = new Array<KeyframeAnimation>();
}
this._registeredAnimations.push(animation);
}
public _unregisterAnimation(animation: KeyframeAnimation) {
if (this._registeredAnimations) {
let index = this._registeredAnimations.indexOf(animation);
if (index >= 0) {
this._registeredAnimations.splice(index, 1);
}
}
}
public _cancelAllAnimations() {
if (this._registeredAnimations) {
for (let animation of this._registeredAnimations) {
animation.cancel();
}
}
}
}
export const visibilityProperty = new CssProperty<Style, "visible" | "hidden" | "collapse" | "collapsed">({
@@ -139,5 +463,30 @@ export const visibilityProperty = new CssProperty<Style, "visible" | "hidden" |
});
visibilityProperty.register(Style);
export let bindingContextProperty = new InheritedProperty<ViewBase, any>({ name: "bindingContext" });
bindingContextProperty.register(ViewBase);
export const bindingContextProperty = new InheritedProperty<ViewBase, any>({ name: "bindingContext" });
bindingContextProperty.register(ViewBase);
function onCssClassPropertyChanged(view: ViewBase, oldValue: string, newValue: string) {
let classes = view.cssClasses;
classes.clear();
if (typeof newValue === "string") {
newValue.split(" ").forEach(c => classes.add(c));
}
}
export const classNameProperty = new Property<ViewBase, string>({ name: "className", valueChanged: onCssClassPropertyChanged });
classNameProperty.register(ViewBase);
function resetStyles(view: ViewBase): void {
// view.style._resetCssValues();
// view._applyStyleFromScope();
view.eachChild((child) => {
// TODO.. Check old implementation....
resetStyles(child);
return true;
});
}
export const idProperty = new Property<ViewBase, string>({ name: "id", valueChanged: (view, oldValue, newValue) => resetStyles(view) });
idProperty.register(ViewBase);

View File

@@ -1,14 +1,12 @@
import { View as ViewDefinition, Point, Size } from "ui/core/view";
import { CssState, StyleScope, applyInlineSyle } from "ui/styling/style-scope";
import { Color } from "color";
import { Animation, AnimationPromise } from "ui/animation";
import { KeyframeAnimation } from "ui/animation/keyframe-animation";
import { Source } from "utils/debug";
import { Background } from "ui/styling/background";
import {
ViewBase, getEventOrGestureName, Observable, EventData, Style, propagateInheritedProperties, clearInheritedProperties,
ViewBase, getEventOrGestureName, Observable, EventData, Style,
Property, InheritedProperty, CssProperty, ShorthandProperty, InheritedCssProperty,
gestureFromString, isIOS
gestureFromString, isIOS, traceEnabled, traceWrite, traceCategories, traceNotifyEvent
} from "./view-base";
import { observe as gestureObserve, GesturesObserver, GestureTypes, GestureEventData } from "ui/gestures";
import { Font, parseFont } from "ui/styling/font";
@@ -16,15 +14,14 @@ import { fontSizeConverter } from "../styling/converters";
// TODO: Remove this and start using string as source (for android).
import { fromFileOrResource, fromBase64, fromUrl } from "image-source";
import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, notifyEvent as traceNotifyEvent } from "trace";
import { isDataURI, isFileOrResourcePath } from "utils/utils";
export * from "./view-base";
export {
Color, GestureTypes, GesturesObserver, GestureEventData, Animation, AnimationPromise, KeyframeAnimation,
Background, Font, traceEnabled, traceWrite, traceCategories, traceNotifyEvent
GestureTypes, GesturesObserver, GestureEventData,
Animation, AnimationPromise,
Background, Font, Color
}
// registerSpecialProperty("class", (instance: ViewDefinition, propertyValue: string) => {
@@ -192,22 +189,17 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
private _parent: ViewCommon;
private _visualState: string;
private _isLoaded: boolean;
private _isLayoutValid: boolean;
private _cssType: string;
private _updatingInheritedProperties: boolean;
private _registeredAnimations: Array<KeyframeAnimation>;
public _domId: number;
public _isAddedToNativeVisualTree: boolean;
public _gestureObservers = {};
public cssClasses: Set<string> = new Set();
public cssPseudoClasses: Set<string> = new Set();
public _cssState: CssState;
public parent: ViewCommon;
constructor() {
@@ -560,22 +552,12 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
//END Style property shortcuts
get page(): ViewDefinition {
if (this.parent) {
return this.parent.page;
}
return null;
}
public id: string;
public automationText: string;
public originX: number;
public originY: number;
public isEnabled: boolean;
public isUserInteractionEnabled: boolean;
public className: string;
get isLayoutValid(): boolean {
return this._isLayoutValid;
@@ -592,49 +574,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
return true;
}
get isLoaded(): boolean {
return this._isLoaded;
}
public onLoaded() {
this._isLoaded = true;
this._loadEachChildView();
this._applyStyleFromScope();
this._emit("loaded");
}
public _loadEachChildView() {
if (this._childrenCount > 0) {
// iterate all children and call onLoaded on them first
let eachChild = function (child: ViewCommon): boolean {
child.onLoaded();
return true;
}
this._eachChildView(eachChild);
}
}
public onUnloaded() {
this._setCssState(null);
this._unloadEachChildView();
this._isLoaded = false;
this._emit("unloaded");
}
public _unloadEachChildView() {
if (this._childrenCount > 0) {
this._eachChildView((child: ViewCommon) => {
if (child.isLoaded) {
child.onUnloaded();
}
return true;
});
}
}
// public _onPropertyChanged(property: Property, oldValue: any, newValue: any) {
// super._onPropertyChanged(property, oldValue, newValue);
@@ -721,44 +660,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
public abstract onLayout(left: number, top: number, right: number, bottom: number): void;
public abstract layoutNativeView(left: number, top: number, right: number, bottom: number): void;
private pseudoClassAliases = {
'highlighted': [
'active',
'pressed'
]
};
private getAllAliasedStates(name: string): Array<string> {
let allStates = [];
allStates.push(name);
if (name in this.pseudoClassAliases) {
for (let i = 0; i < this.pseudoClassAliases[name].length; i++) {
allStates.push(this.pseudoClassAliases[name][i]);
}
}
return allStates;
}
public addPseudoClass(name: string): void {
let allStates = this.getAllAliasedStates(name);
for (let i = 0; i < allStates.length; i++) {
if (!this.cssPseudoClasses.has(allStates[i])) {
this.cssPseudoClasses.add(allStates[i]);
this.notifyPseudoClassChanged(allStates[i]);
}
}
}
public deletePseudoClass(name: string): void {
let allStates = this.getAllAliasedStates(name);
for (let i = 0; i < allStates.length; i++) {
if (this.cssPseudoClasses.has(allStates[i])) {
this.cssPseudoClasses.delete(allStates[i]);
this.notifyPseudoClassChanged(allStates[i]);
}
}
}
public static resolveSizeAndState(size: number, specSize: number, specMode: number, childMeasuredState: number): number {
let result = size;
switch (specMode) {
@@ -975,26 +876,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
return { boundsChanged, sizeChanged };
}
private _applyStyleFromScope() {
let rootPage = this.page;
if (!rootPage || !rootPage.isLoaded) {
return;
}
let scope: StyleScope = (<any>rootPage)._getStyleScope();
scope.applySelectors(this);
}
private _applyInlineStyle(inlineStyle) {
if (typeof inlineStyle === "string") {
try {
// this.style._beginUpdate();
applyInlineSyle(this, inlineStyle);
} finally {
// this.style._endUpdate();
}
}
}
// TODO: We need to implement some kind of build step that includes these members only when building for Android
//@android
public _context: android.content.Context;
@@ -1019,9 +900,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
// TODO: We need to implement some kind of build step that includes these members only when building for iOS
//@endios
get _childrenCount(): number {
return 0;
}
public _eachChildView(callback: (view: ViewCommon) => boolean) {
//
@@ -1047,113 +926,39 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
// IOS specific
}
/**
* Core logic for adding a child view to this instance. Used by the framework to handle lifecycle events more centralized. Do not outside the UI Stack implementation.
* // TODO: Think whether we need the base Layout routine.
*/
public _addView(view: ViewDefinition, atIndex?: number) {
if (traceEnabled) {
traceWrite(`${this}._addView(${view}, ${atIndex})`, traceCategories.ViewHierarchy);
}
if (!view) {
throw new Error("Expecting a valid View instance.");
}
if (!(view instanceof ViewBase)) {
throw new Error(view + " is not a valid View instance.");
}
if (view.parent) {
throw new Error("View already has a parent. View: " + view + " Parent: " + view.parent);
}
view.parent = this;
this._addViewCore(view, atIndex);
view._parentChanged(null);
}
/**
* Method is intended to be overridden by inheritors and used as "protected"
*/
public _addViewCore(view: ViewDefinition, atIndex?: number) {
this._propagateInheritableProperties(view);
public _addViewCore(view: ViewCommon, atIndex?: number) {
if (!view._isAddedToNativeVisualTree) {
let nativeIndex = this._childIndexToNativeChildIndex(atIndex);
view._isAddedToNativeVisualTree = this._addViewToNativeVisualTree(view, nativeIndex);
}
// TODO: Discuss this.
if (this._isLoaded) {
view.onLoaded();
}
}
public _propagateInheritableProperties(view: ViewDefinition) {
propagateInheritedProperties(this);
// view._inheritProperties(this);
// view.style._inheritStyleProperties(this);
}
// public _inheritProperties(parentView: ViewDefinition) {
// parentView._eachSetProperty((property) => {
// if (!(property instanceof styling.Property) && property.inheritable) {
// let baseValue = parentView._getValue(property);
// this._setValue(property, baseValue, ValueSource.Inherited);
// }
// return true;
// });
// }
/**
* Core logic for removing a child view from this instance. Used by the framework to handle lifecycle events more centralized. Do not outside the UI Stack implementation.
*/
public _removeView(view: ViewDefinition) {
if (traceEnabled) {
traceWrite(`${this}._removeView(${view})`, traceCategories.ViewHierarchy);
}
if (view.parent !== this) {
throw new Error("View not added to this instance. View: " + view + " CurrentParent: " + view.parent + " ExpectedParent: " + this);
}
this._removeViewCore(view);
view.parent = undefined;
view._parentChanged(this);
super._addViewCore(view, atIndex);
}
/**
* Method is intended to be overridden by inheritors and used as "protected"
*/
public _removeViewCore(view: ViewDefinition) {
public _removeViewCore(view: ViewCommon) {
// TODO: Change type from ViewCommon to ViewBase. Probably this
// method will need to go to ViewBase class.
// Remove the view from the native visual scene first
this._removeViewFromNativeVisualTree(view);
// TODO: Discuss this.
if (view.isLoaded) {
view.onUnloaded();
}
// view.unsetInheritedProperties();
super._removeViewCore(view);
}
public unsetInheritedProperties(): void {
// this._setValue(ProxyObject.bindingContextProperty, undefined, ValueSource.Inherited);
// this._eachSetProperty((property) => {
// if (!(property instanceof styling.Property) && property.inheritable) {
// this._resetValue(property, ValueSource.Inherited);
// }
// return true;
// });
}
public _parentChanged(oldParent: ViewDefinition): void {
//Overridden
if (oldParent) {
// Move these method in property class.
clearInheritedProperties(this);
}
}
// public unsetInheritedProperties(): void {
// // this._setValue(ProxyObject.bindingContextProperty, undefined, ValueSource.Inherited);
// // this._eachSetProperty((property) => {
// // if (!(property instanceof styling.Property) && property.inheritable) {
// // this._resetValue(property, ValueSource.Inherited);
// // }
// // return true;
// // });
// }
/**
* Method is intended to be overridden by inheritors and used as "protected".
@@ -1173,36 +978,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
view._isAddedToNativeVisualTree = false;
}
public _goToVisualState(state: string) {
if (traceEnabled) {
traceWrite(this + " going to state: " + state, traceCategories.Style);
}
if (state === this._visualState) {
return;
}
this.deletePseudoClass(this._visualState);
this._visualState = state;
this.addPseudoClass(state);
}
public _applyXmlAttribute(attribute, value): boolean {
if (attribute === "style") {
this._applyInlineStyle(value);
return true;
}
return false;
}
public setInlineStyle(style: string): void {
if (typeof style !== "string") {
throw new Error("Parameter should be valid CSS string!");
}
this._applyInlineStyle(style);
}
public _updateLayout() {
// needed for iOS.
}
@@ -1253,30 +1028,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
return new Animation([animation]);
}
public _registerAnimation(animation: KeyframeAnimation) {
if (this._registeredAnimations === undefined) {
this._registeredAnimations = new Array<KeyframeAnimation>();
}
this._registeredAnimations.push(animation);
}
public _unregisterAnimation(animation: KeyframeAnimation) {
if (this._registeredAnimations) {
let index = this._registeredAnimations.indexOf(animation);
if (index >= 0) {
this._registeredAnimations.splice(index, 1);
}
}
}
public _unregisterAllAnimations() {
if (this._registeredAnimations) {
for (let animation of this._registeredAnimations) {
animation.cancel();
}
}
}
public toString(): string {
let str = this.typeName;
if (this.id) {
@@ -1304,88 +1055,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
// // Check for a valid _nativeView instance
// return !!this._nativeView;
// }
private notifyPseudoClassChanged(pseudoClass: string): void {
this.notify({ eventName: ":" + pseudoClass, object: this });
}
// TODO: Make sure the state is set to null and this is called on unloaded to clean up change listeners...
_setCssState(next: CssState): void {
const previous = this._cssState;
this._cssState = next;
if (!this._invalidateCssHandler) {
this._invalidateCssHandler = () => {
if (this._invalidateCssHandlerSuspended) {
return;
}
this.applyCssState();
};
}
try {
this._invalidateCssHandlerSuspended = true;
if (next) {
next.changeMap.forEach((changes, view) => {
if (changes.attributes) {
changes.attributes.forEach(attribute => {
view.addEventListener(attribute + "Change", this._invalidateCssHandler)
});
}
if (changes.pseudoClasses) {
changes.pseudoClasses.forEach(pseudoClass => {
let eventName = ":" + pseudoClass;
view.addEventListener(":" + pseudoClass, this._invalidateCssHandler);
if (view[eventName]) {
view[eventName](+1);
}
});
}
});
}
if (previous) {
previous.changeMap.forEach((changes, view) => {
if (changes.attributes) {
changes.attributes.forEach(attribute => {
view.removeEventListener("onPropertyChanged:" + attribute, this._invalidateCssHandler)
});
}
if (changes.pseudoClasses) {
changes.pseudoClasses.forEach(pseudoClass => {
let eventName = ":" + pseudoClass;
view.removeEventListener(eventName, this._invalidateCssHandler)
if (view[eventName]) {
view[eventName](-1);
}
});
}
});
}
} finally {
this._invalidateCssHandlerSuspended = false;
}
this.applyCssState();
}
/**
* Notify that some attributes or pseudo classes that may affect the current CssState had changed.
*/
private _invalidateCssHandler;
private _invalidateCssHandlerSuspended: boolean;
private applyCssState(): void {
if (!this._cssState) {
return;
}
// this.style._beginUpdate();
this._cssState.apply();
// this.style._endUpdate();
}
}
function getLengthEffectiveValue(density: number, param: Length): number {
@@ -1512,39 +1181,6 @@ export namespace Length {
}
}
function onCssClassPropertyChanged(view: ViewCommon, oldValue: string, newValue: string) {
let classes = view.cssClasses;
classes.clear();
if (typeof newValue === "string") {
newValue.split(" ").forEach(c => classes.add(c));
}
}
export const classNameProperty = new Property<ViewCommon, string>({ name: "className", valueChanged: onCssClassPropertyChanged });
classNameProperty.register(ViewCommon);
function resetStyles(view: ViewCommon): void {
// view.style._resetCssValues();
// view._applyStyleFromScope();
view._eachChildView((child) => {
// TODO.. Check old implementation....
resetStyles(child);
return true;
});
}
export const idProperty = new Property<ViewCommon, string>({ name: "id", valueChanged: (view, oldValue, newValue) => resetStyles(view) });
idProperty.register(ViewCommon);
export const automationTextProperty = new Property<ViewCommon, string>({ name: "automationText" });
automationTextProperty.register(ViewCommon);
export const originXProperty = new Property<ViewCommon, number>({ name: "originX", defaultValue: 0.5, valueConverter: (v) => parseFloat(v) });
originXProperty.register(ViewCommon);
export const originYProperty = new Property<ViewCommon, number>({ name: "originY", defaultValue: 0.5, valueConverter: (v) => parseFloat(v) });
originYProperty.register(ViewCommon);
export function booleanConverter(v: string): boolean {
let lowercase = (v + '').toLowerCase();
if (lowercase === "true") {
@@ -1556,6 +1192,15 @@ export function booleanConverter(v: string): boolean {
throw new Error(`Invalid boolean: ${v}`);
}
export const automationTextProperty = new Property<ViewCommon, string>({ name: "automationText" });
automationTextProperty.register(ViewCommon);
export const originXProperty = new Property<ViewCommon, number>({ name: "originX", defaultValue: 0.5, valueConverter: (v) => parseFloat(v) });
originXProperty.register(ViewCommon);
export const originYProperty = new Property<ViewCommon, number>({ name: "originY", defaultValue: 0.5, valueConverter: (v) => parseFloat(v) });
originYProperty.register(ViewCommon);
export const isEnabledProperty = new Property<ViewCommon, boolean>({ name: "isEnabled", defaultValue: true, valueConverter: booleanConverter });
isEnabledProperty.register(ViewCommon);

View File

@@ -76,15 +76,18 @@ export class View extends ViewCommon {
}
}
public onLoaded() {
protected onLoaded() {
super.onLoaded();
this.setOnTouchListener();
}
public onUnloaded() {
this._nativeView.setOnTouchListener(null);
this.touchListenerIsSet = false;
this._unregisterAllAnimations();
if (this.touchListenerIsSet) {
this._nativeView.setOnTouchListener(null);
this.touchListenerIsSet = false;
}
this._cancelAllAnimations();
super.onUnloaded();
}
@@ -99,12 +102,12 @@ export class View extends ViewCommon {
this._nativeView.setClickable(true);
}
let touchListener = this.touchListener || new TouchListener(new WeakRef(this));
this._nativeView.setOnTouchListener(touchListener);
this.touchListener = this.touchListener || new TouchListener(new WeakRef(this));
this._nativeView.setOnTouchListener(this.touchListener);
}
}
public _addViewCore(view: View, atIndex?: number) {
public _addViewCore(view: ViewCommon, atIndex?: number) {
if (this._context) {
view._onAttached(this._context);
}
@@ -127,6 +130,7 @@ export class View extends ViewCommon {
if (traceEnabled) {
traceWrite(`${this}._onAttached(context)`, traceCategories.VisualTreeEvents);
}
if (this._context === context) {
return;
}
@@ -158,6 +162,9 @@ export class View extends ViewCommon {
return true;
}
this._eachChildView(eachChild);
} else if (this._nativeView) {
// copy all the locally cached values to the native android widget
applyNativeSetters(this);
}
}

View File

@@ -1,18 +1,17 @@
declare module "ui/core/view" {
import { GestureTypes, GesturesObserver, GestureEventData } from "ui/gestures";
import { GestureTypes, GesturesObserver, GestureEventData, TouchGestureEventData, TouchAction } from "ui/gestures";
import { Animation, AnimationDefinition, AnimationPromise } from "ui/animation";
import { KeyframeAnimation } from "ui/animation/keyframe-animation";
import {
ViewBase, Property, CssProperty, InheritedCssProperty, ShorthandProperty, Style,
BindingOptions, Observable, EventData,
ViewBase, Property, CssProperty, InheritedCssProperty, Style,
BindingOptions, Observable, EventData
} from "ui/core/view-base";
import { Background } from "ui/styling/background";
import { Font } from "ui/styling/font";
import { Color } from "color";
export {
GestureTypes, GesturesObserver, GestureEventData,
Animation, AnimationDefinition, AnimationPromise, KeyframeAnimation,
GestureTypes, GesturesObserver, GestureEventData, TouchGestureEventData, TouchAction,
Animation, AnimationDefinition, AnimationPromise,
Background, Font, Color
}
@@ -356,16 +355,6 @@ declare module "ui/core/view" {
cssClasses: Set<string>;
cssPseudoClasses: Set<string>;
/**
* Gets the parent view. This property is read-only.
*/
public parent: View;
/**
* Gets owner page. This is a read-only property.
*/
page: View;
/**
* This is called to find out how big a view should be. The parent supplies constraint information in the width and height parameters.
* The actual measurement work of a view is performed in onMeasure(int, int), called by this method. Therefore, only onMeasure(int, int) can and must be overridden by subclasses.
@@ -550,29 +539,9 @@ declare module "ui/core/view" {
*/
public getActualSize(): Size;
/**
* @protected
* @unstable
* A widget can call this method to add a matching css pseudo class.
*/
public addPseudoClass(name: string): void;
/**
* @protected
* @unstable
* A widget can call this method to discard mathing css pseudo class.
*/
public deletePseudoClass(name: string): void;
// Lifecycle events
onLoaded(): void;
onUnloaded(): void;
isLoaded: boolean;
_addView(view: View, atIndex?: number);
_propagateInheritableProperties(view: View);
// _inheritProperties(parentView: View);
_removeView(view: View);
_context: any /* android.content.Context */;
_childIndexToNativeChildIndex(index?: number): number;
@@ -595,18 +564,11 @@ declare module "ui/core/view" {
isCollapsed: boolean;
isLayoutRequired: boolean;
_parentChanged(oldParent: View): void;
_gestureObservers: any;
// _isInheritedChange(): boolean;
_domId: number;
_cssState: any /* "ui/styling/style-scope" */;
_setCssState(next: any /* "ui/styling/style-scope" */);
_registerAnimation(animation: KeyframeAnimation);
_unregisterAnimation(animation: KeyframeAnimation);
_unregisterAllAnimations();
_isAddedToNativeVisualTree: boolean;
/**
@@ -740,8 +702,6 @@ declare module "ui/core/view" {
export function measureSpecToString(measureSpec: number): string;
}
export const classNameProperty: Property<View, string>;
export const idProperty: Property<View, string>;
export const automationTextProperty: Property<View, string>;
export const originXProperty: Property<View, number>;
export const originYProperty: Property<View, number>;