diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index af30e1be2..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ - "typescript.tsdk": "node_modules/typescript/lib" -} \ No newline at end of file diff --git a/tests/.vscode/launch.json b/tests/.vscode/launch.json index 95cc172ed..abcaa7450 100644 --- a/tests/.vscode/launch.json +++ b/tests/.vscode/launch.json @@ -1,77 +1,41 @@ { "version": "0.2.0", "configurations": [ - { - "name": "Sync on iOS", - "type": "nativescript", - "platform": "ios", - "request": "launch", - "appRoot": "${workspaceRoot}", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false, - "rebuild": false, - "syncAllFiles": true, - "stopOnEntry": true - }, { "name": "Launch on iOS", "type": "nativescript", - "platform": "ios", "request": "launch", + "platform": "ios", "appRoot": "${workspaceRoot}", "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false, - "rebuild": true, - "stopOnEntry": true + "watch": true }, { "name": "Attach on iOS", "type": "nativescript", - "platform": "ios", "request": "attach", + "platform": "ios", "appRoot": "${workspaceRoot}", "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false, - "stopOnEntry": true - }, - { - "name": "Sync on Android", - "type": "nativescript", - "platform": "android", - "request": "launch", - "appRoot": "${workspaceRoot}", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false, - "rebuild": false, - "syncAllFiles": true, - "stopOnEntry": true + "watch": false }, { "name": "Launch on Android", "type": "nativescript", - "platform": "android", "request": "launch", + "platform": "android", "appRoot": "${workspaceRoot}", "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false, - "rebuild": true, - "stopOnEntry": true + "watch": true }, { "name": "Attach on Android", "type": "nativescript", - "platform": "android", "request": "attach", + "platform": "android", "appRoot": "${workspaceRoot}", "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false, - "stopOnEntry": true + "watch": false } ] } \ No newline at end of file diff --git a/tests/.vscode/settings.json b/tests/.vscode/settings.json deleted file mode 100644 index c7c1623bc..000000000 --- a/tests/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "typescript.tsdk": "./node_modules/typescript/lib" -} \ No newline at end of file diff --git a/tests/package.json b/tests/package.json index 58fa869a2..9a250763b 100644 --- a/tests/package.json +++ b/tests/package.json @@ -6,14 +6,14 @@ "nativescript": { "id": "org.nativescript.tests", "tns-ios": { - "version": "2.4.0" + "version": "2.5.0" }, "tns-android": { - "version": "2.4.1" + "version": "2.5.0" } }, "dependencies": { - "tns-core-modules": "2.4.0" + "tns-core-modules": "2.5.0" }, "devDependencies": { "tns-platform-declarations": "*", @@ -24,4 +24,4 @@ "lazy": "1.0.11", "typescript": "~2.0.10" } -} \ No newline at end of file +} diff --git a/tns-core-modules/ui/core/properties.ts b/tns-core-modules/ui/core/properties.ts index ab899e770..344ccb7be 100644 --- a/tns-core-modules/ui/core/properties.ts +++ b/tns-core-modules/ui/core/properties.ts @@ -38,7 +38,7 @@ const enum ValueSource { Local = 3 } -export class Property implements PropertyDescriptor, definitions.Property { +export class Property implements TypedPropertyDescriptor, definitions.Property { private registered: boolean; public readonly name: string; @@ -174,40 +174,20 @@ export class Property implements PropertyDescriptor, defi } } -export class CoercibleProperty implements PropertyDescriptor, definitions.CoercibleProperty { - 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 extends Property implements definitions.CoercibleProperty { public readonly coerce: (target: T) => void; constructor(options: definitions.CoerciblePropertyOptions) { + 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 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 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 = (Object).getOwnPropertySymbols(view); for (let symbol of symbols) { const property: Property = symbolPropertyMap[symbol]; @@ -873,6 +814,44 @@ export function applyNativeSetters(view: ViewBase): void { } } +export function resetNativeView(view: ViewBase): void { + let symbols = (Object).getOwnPropertySymbols(view); + for (let symbol of symbols) { + const property: Property = 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 = (Object).getOwnPropertySymbols(style); + for (let symbol of symbols) { + const property: CssProperty = 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 = (Object).getOwnPropertySymbols(style); - const view = style.view; - for (let symbol of symbols) { - const property: CssProperty = 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(isValid: (value: any) => boolean): (value: any) => throw new Error("Invalid value: " + value); } }; -} \ No newline at end of file +} diff --git a/tns-core-modules/ui/core/view-base.ts b/tns-core-modules/ui/core/view-base.ts index ac96671e4..285afed01 100644 --- a/tns-core-modules/ui/core/view-base.ts +++ b/tns-core-modules/ui/core/view-base.ts @@ -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; @@ -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); } diff --git a/tns-core-modules/ui/definitions.d.ts b/tns-core-modules/ui/definitions.d.ts index fd4b26b2d..0de01aadf 100644 --- a/tns-core-modules/ui/definitions.d.ts +++ b/tns-core-modules/ui/definitions.d.ts @@ -54,6 +54,7 @@ declare module "ui/core/view-base" { public android: any; public nativeView: any; public bindingContext: any; + public recycleNativeView: boolean; /** * Gets the name of the constructor function for this instance. E.g. for a Button class this will return "Button". @@ -225,14 +226,10 @@ declare module "ui/core/properties" { public nativeValueChange(T, U): void; } - export class CoercibleProperty implements TypedPropertyDescriptor { + export class CoercibleProperty extends Property implements TypedPropertyDescriptor { constructor(options: CoerciblePropertyOptions); - public readonly native: symbol; - public readonly defaultValue: U; public readonly coerce: (target: T) => void; - public register(cls: { prototype: T }): void; - public nativeValueChange(T, U): void; } export class InheritedProperty extends Property { @@ -269,8 +266,8 @@ declare module "ui/core/properties" { public register(cls: { prototype: T }): void; } - export function applyNativeSetters(view: ViewBase): void; - export function resetStyleProperties(style: Style): void; + export function initNativeView(view: ViewBase): void; + export function resetNativeView(view: ViewBase): void; export function resetCSSProperties(style: Style): void; export function makeValidator(...values: T[]): (value: any) => value is T; diff --git a/tns-core-modules/ui/label/label.ios.ts b/tns-core-modules/ui/label/label.ios.ts index 60d5e5ce8..a18beb131 100644 --- a/tns-core-modules/ui/label/label.ios.ts +++ b/tns-core-modules/ui/label/label.ios.ts @@ -64,7 +64,7 @@ export class Label extends TextBase implements LabelDefinition { } public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void { - let nativeView = this._nativeView; + let nativeView = this.nativeView; if (nativeView) { let width = layout.getMeasureSpecSize(widthMeasureSpec); let widthMode = layout.getMeasureSpecMode(widthMeasureSpec); @@ -119,33 +119,23 @@ export class Label extends TextBase implements LabelDefinition { } } - get [backgroundInternalProperty.native](): UIColor { - let nativeView = this._nativeView; - if (nativeView.layer && nativeView.layer.backgroundColor) { - return UIColor.colorWithCGColor(nativeView.layer.backgroundColor); - } - - return undefined; + get [backgroundInternalProperty.native](): any /* CGColor */ { + return this.nativeView.layer.backgroundColor; } - set [backgroundInternalProperty.native](value: UIColor | Background) { - let nativeView = this._nativeView; - - let cgColor = null; - if (value instanceof UIColor) { - cgColor = value.CGColor; - } else { - let uiColor = ios.createBackgroundUIColor(this, true); - cgColor = uiColor ? uiColor.CGColor : null; + set [backgroundInternalProperty.native](value: Background) { + if (value instanceof Background) { + const uiColor = ios.createBackgroundUIColor(this, true); + value = uiColor ? uiColor.CGColor : null; } - nativeView.layer.backgroundColor = cgColor; + this.nativeView.layer.backgroundColor = value; } get [borderTopWidthProperty.native](): Length { return zeroLength; } set [borderTopWidthProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let border = nativeView.borderThickness; nativeView.borderThickness = { top: this.effectiveBorderTopWidth, @@ -159,7 +149,7 @@ export class Label extends TextBase implements LabelDefinition { return zeroLength; } set [borderRightWidthProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let border = nativeView.borderThickness; nativeView.borderThickness = { top: border.top, @@ -173,7 +163,7 @@ export class Label extends TextBase implements LabelDefinition { return zeroLength; } set [borderBottomWidthProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let border = nativeView.borderThickness; nativeView.borderThickness = { top: border.top, @@ -187,7 +177,7 @@ export class Label extends TextBase implements LabelDefinition { return zeroLength; } set [borderLeftWidthProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let border = nativeView.borderThickness; nativeView.borderThickness = { top: border.top, @@ -201,7 +191,7 @@ export class Label extends TextBase implements LabelDefinition { return zeroLength; } set [paddingTopProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let padding = nativeView.padding; nativeView.padding = { top: this.effectivePaddingTop, @@ -215,7 +205,7 @@ export class Label extends TextBase implements LabelDefinition { return zeroLength; } set [paddingRightProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let padding = nativeView.padding; nativeView.padding = { top: padding.top, @@ -229,7 +219,7 @@ export class Label extends TextBase implements LabelDefinition { return zeroLength; } set [paddingBottomProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let padding = nativeView.padding; nativeView.padding = { top: padding.top, @@ -243,7 +233,7 @@ export class Label extends TextBase implements LabelDefinition { return zeroLength; } set [paddingLeftProperty.native](value: Length) { - let nativeView = this._nativeView; + let nativeView = this.nativeView; let padding = nativeView.padding; nativeView.padding = { top: padding.top, diff --git a/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts b/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts index 60359fda2..d0cbccf0a 100644 --- a/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts +++ b/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts @@ -1,6 +1,6 @@ import { SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty, - colorProperty, fontInternalProperty, fontSizeProperty, Color, Font, applyNativeSetters + colorProperty, fontInternalProperty, fontSizeProperty, Color, Font, initNativeView } from "./segmented-bar-common"; export * from "./segmented-bar-common"; @@ -64,7 +64,7 @@ export class SegmentedBarItem extends SegmentedBarItemBase { this._textView = titleTextView; if (titleTextView) { - applyNativeSetters(this); + initNativeView(this); if (this.titleDirty) { this._update(); } diff --git a/tns-core-modules/ui/styling/background.ios.ts b/tns-core-modules/ui/styling/background.ios.ts index 212f6d291..39aa5ae01 100644 --- a/tns-core-modules/ui/styling/background.ios.ts +++ b/tns-core-modules/ui/styling/background.ios.ts @@ -3,222 +3,143 @@ import { ios as utilsIos } from "utils/utils"; export * from "./background-common"; +interface NativeView extends UIView { + hasNonUniformBorder: boolean; + topBorderLayer: CAShapeLayer; + rightBorderLayer: CAShapeLayer; + bottomBorderLayer: CAShapeLayer; + leftBorderLayer: CAShapeLayer; +} + +interface Rect { + left: number; + top: number; + right: number; + bottom: number; +} + +const clearCGColor = utilsIos.getter(UIColor, UIColor.clearColor).CGColor; + export module ios { export function createBackgroundUIColor(view: View, flip?: boolean): UIColor { - let background = view.style.backgroundInternal; - if (background.isEmpty()) { - return undefined; + const background = view.style.backgroundInternal; + const nativeView = view.nativeView; + + if (background.hasUniformBorder()) { + if (nativeView.hasNonUniformBorder) { + clearNonUniformBorders(nativeView); + } + + const layer = nativeView.layer; + const borderColor = background.getUniformBorderColor(); + layer.borderColor = !borderColor ? undefined : borderColor.ios.CGColor; + layer.borderWidth = background.getUniformBorderWidth(); + layer.cornerRadius = background.getUniformBorderRadius(); + } + else { + drawNonUniformBorders(nativeView, background); } - let nativeView = view.nativeView; - // Clip-path + // Clip-path should be called after borders are applied. + // It will eventually move them to different layer if uniform. if (background.clipPath) { drawClipPath(nativeView, background); } - // Borders - - // Clear all borders - nativeView.layer.borderColor = undefined; - nativeView.layer.borderWidth = 0; - nativeView.layer.cornerRadius = 0; - nativeView.clipsToBounds = true; - - if (nativeView["topBorderLayer"]){ - (nativeView["topBorderLayer"]).removeFromSuperlayer(); - } - - if (nativeView["rightBorderLayer"]){ - (nativeView["rightBorderLayer"]).removeFromSuperlayer(); - } - - if (nativeView["bottomBorderLayer"]){ - (nativeView["bottomBorderLayer"]).removeFromSuperlayer(); - } - - if (nativeView["leftBorderLayer"]){ - (nativeView["leftBorderLayer"]).removeFromSuperlayer(); - } - - // Clip-path - if (background.clipPath) { - drawClipPath(nativeView, background); - } - - if (background.hasUniformBorder()){ - let borderColor = background.getUniformBorderColor(); - if (borderColor && borderColor.ios){ - nativeView.layer.borderColor = borderColor.ios.CGColor; - } - else { - nativeView.layer.borderColor = undefined; - } - nativeView.layer.borderWidth = background.getUniformBorderWidth(); - nativeView.layer.cornerRadius = background.getUniformBorderRadius(); - } - else { // Draw non-uniform borders - let nativeViewLayerBounds = { - left: nativeView.layer.bounds.origin.x, - top: nativeView.layer.bounds.origin.y, - bottom: nativeView.layer.bounds.size.height, - right: nativeView.layer.bounds.size.width - }; - - let top = background.borderTopWidth; - let right = background.borderRightWidth; - let bottom = background.borderBottomWidth; - let left = background.borderLeftWidth; - - let lto: Point = {x: nativeViewLayerBounds.left, y: nativeViewLayerBounds.top};// left-top-outside - let lti: Point = {x: nativeViewLayerBounds.left + left, y: nativeViewLayerBounds.top + top}; // left-top-inside - - let rto: Point = {x: nativeViewLayerBounds.right, y: nativeViewLayerBounds.top}; // right-top-outside - let rti: Point = {x: nativeViewLayerBounds.right - right, y: nativeViewLayerBounds.top + top}; // right-top-inside - - let rbo: Point = {x: nativeViewLayerBounds.right, y: nativeViewLayerBounds.bottom}; // right-bottom-outside - let rbi: Point = {x: nativeViewLayerBounds.right - right, y: nativeViewLayerBounds.bottom - bottom}; // right-bottom-inside - - let lbo: Point = {x: nativeViewLayerBounds.left, y: nativeViewLayerBounds.bottom}; // left-bottom-outside - let lbi: Point = {x: nativeViewLayerBounds.left + left, y: nativeViewLayerBounds.bottom - bottom}; // left-bottom-inside - - if (top > 0 && background.borderTopColor && background.borderTopColor.ios){ - let topBorderPath = CGPathCreateMutable(); - CGPathMoveToPoint(topBorderPath, null, lto.x, lto.y); - CGPathAddLineToPoint(topBorderPath, null, rto.x, rto.y); - CGPathAddLineToPoint(topBorderPath, null, rti.x, rti.y); - CGPathAddLineToPoint(topBorderPath, null, lti.x, lti.y); - CGPathAddLineToPoint(topBorderPath, null, lto.x, lto.y); - - let topBorderLayer = CAShapeLayer.layer(); - topBorderLayer.fillColor = background.borderTopColor.ios.CGColor; - topBorderLayer.path = topBorderPath; - - nativeView.layer.addSublayer(topBorderLayer); - nativeView["topBorderLayer"] = topBorderLayer; - } - - if (right > 0 && background.borderRightColor && background.borderRightColor.ios){ - let rightBorderPath = CGPathCreateMutable(); - CGPathMoveToPoint(rightBorderPath, null, rto.x, rto.y); - CGPathAddLineToPoint(rightBorderPath, null, rbo.x, rbo.y); - CGPathAddLineToPoint(rightBorderPath, null, rbi.x, rbi.y); - CGPathAddLineToPoint(rightBorderPath, null, rti.x, rti.y); - CGPathAddLineToPoint(rightBorderPath, null, rto.x, rto.y); - - let rightBorderLayer = CAShapeLayer.layer(); - rightBorderLayer.fillColor = background.borderRightColor.ios.CGColor; - rightBorderLayer.path = rightBorderPath; - - nativeView.layer.addSublayer(rightBorderLayer); - nativeView["rightBorderLayer"] = rightBorderLayer; - } - - if (bottom > 0 && background.borderBottomColor && background.borderBottomColor.ios){ - let bottomBorderPath = CGPathCreateMutable(); - CGPathMoveToPoint(bottomBorderPath, null, rbo.x, rbo.y); - CGPathAddLineToPoint(bottomBorderPath, null, lbo.x, lbo.y); - CGPathAddLineToPoint(bottomBorderPath, null, lbi.x, lbi.y); - CGPathAddLineToPoint(bottomBorderPath, null, rbi.x, rbi.y); - CGPathAddLineToPoint(bottomBorderPath, null, rbo.x, rbo.y); - - let bottomBorderLayer = CAShapeLayer.layer(); - bottomBorderLayer.fillColor = background.borderBottomColor.ios.CGColor; - bottomBorderLayer.path = bottomBorderPath; - - nativeView.layer.addSublayer(bottomBorderLayer); - nativeView["bottomBorderLayer"] = bottomBorderLayer; - } - - if (left > 0 && background.borderLeftColor && background.borderLeftColor.ios){ - let leftBorderPath = CGPathCreateMutable(); - CGPathMoveToPoint(leftBorderPath, null, lbo.x, lbo.y); - CGPathAddLineToPoint(leftBorderPath, null, lto.x, lto.y); - CGPathAddLineToPoint(leftBorderPath, null, lti.x, lti.y); - CGPathAddLineToPoint(leftBorderPath, null, lbi.x, lbi.y); - CGPathAddLineToPoint(leftBorderPath, null, lbo.x, lbo.y); - - let leftBorderLayer = CAShapeLayer.layer(); - leftBorderLayer.fillColor = background.borderLeftColor.ios.CGColor; - leftBorderLayer.path = leftBorderPath; - - nativeView.layer.addSublayer(leftBorderLayer); - nativeView["leftBorderLayer"] = leftBorderLayer; - } - } - if (!background.image) { return background.color ? background.color.ios : undefined; + } else { + return getUIColorFromImage(view, nativeView, background, flip); } + } +} - let frame = nativeView.frame; - let boundsWidth = view.scaleX ? frame.size.width / view.scaleX : frame.size.width; - let boundsHeight = view.scaleY ? frame.size.height / view.scaleY : frame.size.height; - if (!boundsWidth || !boundsHeight) { - return undefined; - } - - // We have an image for a background - let img = background.image.ios; - let params = background.getDrawParams(boundsWidth, boundsHeight); - - if (params.sizeX > 0 && params.sizeY > 0) { - let resizeRect = CGRectMake(0, 0, params.sizeX, params.sizeY); - UIGraphicsBeginImageContext(resizeRect.size); - img.drawInRect(resizeRect); - img = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - } - - UIGraphicsBeginImageContextWithOptions(CGSizeFromString(`{${boundsWidth},${boundsHeight}}`), false, 0.0); - let context = UIGraphicsGetCurrentContext(); - - if (background.color && background.color.ios) { - CGContextSetFillColorWithColor(context, background.color.ios.CGColor); - CGContextFillRect(context, CGRectMake(0, 0, boundsWidth, boundsHeight)); - } - - if (!params.repeatX && !params.repeatY) { - img.drawAtPoint(CGPointMake(params.posX, params.posY)); - } - else { - let w = params.repeatX ? boundsWidth : img.size.width; - let h = params.repeatY ? boundsHeight : img.size.height; - - CGContextSetPatternPhase(context, CGSizeMake(params.posX, params.posY)); - - params.posX = params.repeatX ? 0 : params.posX; - params.posY = params.repeatY ? 0 : params.posY; - - let patternRect = CGRectMake(params.posX, params.posY, w, h); - - img.drawAsPatternInRect(patternRect); - } - - let bkgImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - if (flip) { - let flippedImage = _flipImage(bkgImage); - return UIColor.alloc().initWithPatternImage(flippedImage); - } - - return UIColor.alloc().initWithPatternImage(bkgImage); +function clearNonUniformBorders(nativeView: NativeView): void { + if (nativeView.topBorderLayer) { + nativeView.topBorderLayer.removeFromSuperlayer(); } - // Flipping the default coordinate system - // https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html - function _flipImage(originalImage: UIImage): UIImage { - UIGraphicsBeginImageContextWithOptions(originalImage.size, false, 0.0); - let context = UIGraphicsGetCurrentContext(); - CGContextSaveGState(context); - CGContextTranslateCTM(context, 0.0, originalImage.size.height); - CGContextScaleCTM(context, 1.0, -1.0); - originalImage.drawInRect(CGRectMake(0, 0, originalImage.size.width, originalImage.size.height)) - CGContextRestoreGState(context); - let flippedImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return flippedImage; + if (nativeView.rightBorderLayer) { + nativeView.rightBorderLayer.removeFromSuperlayer(); } + + if (nativeView.bottomBorderLayer) { + nativeView.bottomBorderLayer.removeFromSuperlayer(); + } + + if (nativeView.leftBorderLayer) { + nativeView.leftBorderLayer.removeFromSuperlayer(); + } +} + +function getUIColorFromImage(view: View, nativeView: UIView, background: Background, flip?: boolean): UIColor { + const frame = nativeView.frame; + const boundsWidth = view.scaleX ? frame.size.width / view.scaleX : frame.size.width; + const boundsHeight = view.scaleY ? frame.size.height / view.scaleY : frame.size.height; + if (!boundsWidth || !boundsHeight) { + return undefined; + } + + // We have an image for a background + let img = background.image.ios; + const params = background.getDrawParams(boundsWidth, boundsHeight); + + if (params.sizeX > 0 && params.sizeY > 0) { + const resizeRect = CGRectMake(0, 0, params.sizeX, params.sizeY); + UIGraphicsBeginImageContext(resizeRect.size); + img.drawInRect(resizeRect); + img = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + + UIGraphicsBeginImageContextWithOptions(CGSizeFromString(`{${boundsWidth},${boundsHeight}}`), false, 0.0); + const context = UIGraphicsGetCurrentContext(); + + if (background.color && background.color.ios) { + CGContextSetFillColorWithColor(context, background.color.ios.CGColor); + CGContextFillRect(context, CGRectMake(0, 0, boundsWidth, boundsHeight)); + } + + if (!params.repeatX && !params.repeatY) { + img.drawAtPoint(CGPointMake(params.posX, params.posY)); + } else { + const w = params.repeatX ? boundsWidth : img.size.width; + const h = params.repeatY ? boundsHeight : img.size.height; + + CGContextSetPatternPhase(context, CGSizeMake(params.posX, params.posY)); + + params.posX = params.repeatX ? 0 : params.posX; + params.posY = params.repeatY ? 0 : params.posY; + + const patternRect = CGRectMake(params.posX, params.posY, w, h); + + img.drawAsPatternInRect(patternRect); + } + + const bkgImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + if (flip) { + const flippedImage = _flipImage(bkgImage); + return UIColor.alloc().initWithPatternImage(flippedImage); + } + + return UIColor.alloc().initWithPatternImage(bkgImage); +} + +// Flipping the default coordinate system +// https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html +function _flipImage(originalImage: UIImage): UIImage { + UIGraphicsBeginImageContextWithOptions(originalImage.size, false, 0.0); + const context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); + CGContextTranslateCTM(context, 0.0, originalImage.size.height); + CGContextScaleCTM(context, 1.0, -1.0); + originalImage.drawInRect(CGRectMake(0, 0, originalImage.size.width, originalImage.size.height)) + CGContextRestoreGState(context); + const flippedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return flippedImage; } function cssValueToDevicePixels(source: string, total: number): number { @@ -236,137 +157,283 @@ function cssValueToDevicePixels(source: string, total: number): number { return layout.toDevicePixels(result); } -function drawClipPath(nativeView: UIView, background: Background) { - let path: any; +function drawNonUniformBorders(nativeView: NativeView, background: Background) { + const layer = nativeView.layer; + layer.borderColor = undefined; + layer.borderWidth = 0; + layer.cornerRadius = 0; + nativeView.clipsToBounds = true; - let bounds = { - left: nativeView.bounds.origin.x, - top: nativeView.bounds.origin.y, - bottom: nativeView.bounds.size.height, - right: nativeView.bounds.size.width + const layerBounds = layer.bounds; + const layerOrigin = layerBounds.origin; + const layerSize = layerBounds.size; + + const nativeViewLayerBounds = { + left: layerOrigin.x, + top: layerOrigin.y, + bottom: layerSize.height, + right: layerSize.width + }; + + const top = background.borderTopWidth; + const right = background.borderRightWidth; + const bottom = background.borderBottomWidth; + const left = background.borderLeftWidth; + + const lto: Point = { x: nativeViewLayerBounds.left, y: nativeViewLayerBounds.top };// left-top-outside + const lti: Point = { x: nativeViewLayerBounds.left + left, y: nativeViewLayerBounds.top + top }; // left-top-inside + + const rto: Point = { x: nativeViewLayerBounds.right, y: nativeViewLayerBounds.top }; // right-top-outside + const rti: Point = { x: nativeViewLayerBounds.right - right, y: nativeViewLayerBounds.top + top }; // right-top-inside + + const rbo: Point = { x: nativeViewLayerBounds.right, y: nativeViewLayerBounds.bottom }; // right-bottom-outside + const rbi: Point = { x: nativeViewLayerBounds.right - right, y: nativeViewLayerBounds.bottom - bottom }; // right-bottom-inside + + const lbo: Point = { x: nativeViewLayerBounds.left, y: nativeViewLayerBounds.bottom }; // left-bottom-outside + const lbi: Point = { x: nativeViewLayerBounds.left + left, y: nativeViewLayerBounds.bottom - bottom }; // left-bottom-inside + + let hasNonUniformBorder: boolean; + const borderTopColor = background.borderTopColor; + if (top > 0 && borderTopColor && borderTopColor.ios) { + const topBorderPath = CGPathCreateMutable(); + CGPathMoveToPoint(topBorderPath, null, lto.x, lto.y); + CGPathAddLineToPoint(topBorderPath, null, rto.x, rto.y); + CGPathAddLineToPoint(topBorderPath, null, rti.x, rti.y); + CGPathAddLineToPoint(topBorderPath, null, lti.x, lti.y); + CGPathAddLineToPoint(topBorderPath, null, lto.x, lto.y); + + const topBorderLayer = CAShapeLayer.layer(); + topBorderLayer.fillColor = background.borderTopColor.ios.CGColor; + topBorderLayer.path = topBorderPath; + + layer.addSublayer(topBorderLayer); + nativeView.topBorderLayer = topBorderLayer; + hasNonUniformBorder = true; + } else if (nativeView.topBorderLayer) { + nativeView.topBorderLayer.removeFromSuperlayer(); + } + + const borderRightColor = background.borderRightColor; + if (right > 0 && borderRightColor && borderRightColor.ios) { + const rightBorderPath = CGPathCreateMutable(); + CGPathMoveToPoint(rightBorderPath, null, rto.x, rto.y); + CGPathAddLineToPoint(rightBorderPath, null, rbo.x, rbo.y); + CGPathAddLineToPoint(rightBorderPath, null, rbi.x, rbi.y); + CGPathAddLineToPoint(rightBorderPath, null, rti.x, rti.y); + CGPathAddLineToPoint(rightBorderPath, null, rto.x, rto.y); + + const rightBorderLayer = CAShapeLayer.layer(); + rightBorderLayer.fillColor = background.borderRightColor.ios.CGColor; + rightBorderLayer.path = rightBorderPath; + + layer.addSublayer(rightBorderLayer); + nativeView.rightBorderLayer = rightBorderLayer; + hasNonUniformBorder = true; + } else if (nativeView.rightBorderLayer) { + nativeView.rightBorderLayer.removeFromSuperlayer(); + } + + const borderBottomColor = background.borderBottomColor; + if (bottom > 0 && borderBottomColor && borderBottomColor.ios) { + const bottomBorderPath = CGPathCreateMutable(); + CGPathMoveToPoint(bottomBorderPath, null, rbo.x, rbo.y); + CGPathAddLineToPoint(bottomBorderPath, null, lbo.x, lbo.y); + CGPathAddLineToPoint(bottomBorderPath, null, lbi.x, lbi.y); + CGPathAddLineToPoint(bottomBorderPath, null, rbi.x, rbi.y); + CGPathAddLineToPoint(bottomBorderPath, null, rbo.x, rbo.y); + + const bottomBorderLayer = CAShapeLayer.layer(); + bottomBorderLayer.fillColor = background.borderBottomColor.ios.CGColor; + bottomBorderLayer.path = bottomBorderPath; + + layer.addSublayer(bottomBorderLayer); + nativeView.bottomBorderLayer = bottomBorderLayer; + hasNonUniformBorder = true; + } else if (nativeView.bottomBorderLayer) { + nativeView.bottomBorderLayer.removeFromSuperlayer(); + } + + const borderLeftColor = background.borderLeftColor; + if (left > 0 && borderLeftColor && borderLeftColor.ios) { + const leftBorderPath = CGPathCreateMutable(); + CGPathMoveToPoint(leftBorderPath, null, lbo.x, lbo.y); + CGPathAddLineToPoint(leftBorderPath, null, lto.x, lto.y); + CGPathAddLineToPoint(leftBorderPath, null, lti.x, lti.y); + CGPathAddLineToPoint(leftBorderPath, null, lbi.x, lbi.y); + CGPathAddLineToPoint(leftBorderPath, null, lbo.x, lbo.y); + + const leftBorderLayer = CAShapeLayer.layer(); + leftBorderLayer.fillColor = background.borderLeftColor.ios.CGColor; + leftBorderLayer.path = leftBorderPath; + + layer.addSublayer(leftBorderLayer); + nativeView.leftBorderLayer = leftBorderLayer; + hasNonUniformBorder = true; + } else if (nativeView.leftBorderLayer) { + nativeView.leftBorderLayer.removeFromSuperlayer(); + } + + nativeView.hasNonUniformBorder = hasNonUniformBorder; +} + +function drawClipPath(nativeView: UIView, background: Background) { + const layer = nativeView.layer; + const layerBounds = layer.bounds; + const layerOrigin = layerBounds.origin; + const layerSize = layerBounds.size; + + const bounds = { + left: layerOrigin.x, + top: layerOrigin.y, + bottom: layerSize.height, + right: layerSize.width }; if (bounds.right === 0 || bounds.bottom === 0) { return; } - let clipPath = background.clipPath; + let path: UIBezierPath; + const clipPath = background.clipPath; - let functionName = clipPath.substring(0, clipPath.indexOf("(")); - let value = clipPath.replace(`${functionName}(`, "").replace(")", ""); + const functionName = clipPath.substring(0, clipPath.indexOf("(")); + const value = clipPath.replace(`${functionName}(`, "").replace(")", ""); - if (functionName === "rect") { - let arr = value.split(/[\s]+/); + switch (functionName) { + case "rect": + path = rectPath(value, bounds); + break; - let top = cssValueToDevicePixels(arr[0], bounds.top); - let left = cssValueToDevicePixels(arr[1], bounds.left); - let bottom = cssValueToDevicePixels(arr[2], bounds.bottom); - let right = cssValueToDevicePixels(arr[3], bounds.right); + case "inset": + path = insetPath(value, bounds); + break; - path = UIBezierPath.bezierPathWithRect(CGRectMake(left, top, right - left, bottom - top)).CGPath; - } - else if (functionName === "inset") { - let arr = value.split(/[\s]+/); - - let topString: string; - let rightString: string; - let bottomString: string; - let leftString: string; - if (arr.length === 1) { - topString = rightString = bottomString = leftString = arr[0]; - } - else if (arr.length === 2) { - topString = bottomString = arr[0]; - rightString = leftString = arr[1]; - } - else if (arr.length === 3) { - topString = arr[0]; - rightString = leftString = arr[1]; - bottomString = arr[2]; - } - else if (arr.length === 4) { - topString = arr[0]; - rightString = arr[1]; - bottomString = arr[2]; - leftString = arr[3]; - } + case "circle": + path = circlePath(value, bounds); + break; - let top = cssValueToDevicePixels(topString, bounds.bottom); - let right = cssValueToDevicePixels("100%", bounds.right) - cssValueToDevicePixels(rightString, bounds.right); - let bottom = cssValueToDevicePixels("100%", bounds.bottom) - cssValueToDevicePixels(bottomString, bounds.bottom); - let left = cssValueToDevicePixels(leftString, bounds.right); + case "ellipse": + path = ellipsePath(value, bounds); + break; - path = UIBezierPath.bezierPathWithRect(CGRectMake(left, top, right - left, bottom - top)).CGPath; - } - else if (functionName === "circle") { - let arr = value.split(/[\s]+/); - - let radius = cssValueToDevicePixels(arr[0], (bounds.right > bounds.bottom ? bounds.bottom : bounds.right) / 2); - let y = cssValueToDevicePixels(arr[2], bounds.bottom); - let x = cssValueToDevicePixels(arr[3], bounds.right); - - path = UIBezierPath.bezierPathWithArcCenterRadiusStartAngleEndAngleClockwise(CGPointMake(x, y), radius, 0, 360, true).CGPath; - - } else if (functionName === "ellipse") { - let arr = value.split(/[\s]+/); - - let rX = cssValueToDevicePixels(arr[0], bounds.right); - let rY = cssValueToDevicePixels(arr[1], bounds.bottom); - let cX = cssValueToDevicePixels(arr[3], bounds.right); - let cY = cssValueToDevicePixels(arr[4], bounds.bottom); - - let left = cX - rX; - let top = cY - rY; - let width = rX * 2; - let height = rY * 2; - - path = UIBezierPath.bezierPathWithOvalInRect(CGRectMake(left, top, width, height)).CGPath; - - } - else if (functionName === "polygon") { - - path = CGPathCreateMutable() - - let firstPoint: Point; - let arr = value.split(/[,]+/); - for (let i = 0; i < arr.length; i++) { - let xy = arr[i].trim().split(/[\s]+/); - let point: Point = { - x: cssValueToDevicePixels(xy[0], bounds.right), - y: cssValueToDevicePixels(xy[1], bounds.bottom) - }; - - if (!firstPoint) { - firstPoint = point; - CGPathMoveToPoint(path, null, point.x, point.y) - } - - CGPathAddLineToPoint(path, null, point.x, point.y) - } - - CGPathAddLineToPoint(path, null, firstPoint.x, firstPoint.y) + case "polygon": + path = polygonPath(value, bounds); + break; } if (path) { - let shape = CAShapeLayer.layer(); + const shape = CAShapeLayer.layer(); shape.path = path; - nativeView.layer.mask = shape; + layer.mask = shape; nativeView.clipsToBounds = true; - let borderWidth = background.getUniformBorderWidth(); - let borderColor = background.getUniformBorderColor(); + const borderWidth = background.getUniformBorderWidth(); + const borderColor = background.getUniformBorderColor(); - if (borderWidth > 0 && borderColor instanceof Color){ - let borderLayer = CAShapeLayer.layer(); + if (borderWidth > 0 && borderColor instanceof Color) { + const borderLayer = CAShapeLayer.layer(); borderLayer.path = path; borderLayer.lineWidth = borderWidth * 2; borderLayer.strokeColor = borderColor.ios.CGColor; - borderLayer.fillColor = utilsIos.getter(UIColor, UIColor.clearColor).CGColor; + borderLayer.fillColor = clearCGColor; borderLayer.frame = nativeView.bounds; - nativeView.layer.borderColor = undefined; - nativeView.layer.borderWidth = 0; - nativeView.layer.addSublayer(borderLayer); + layer.borderColor = undefined; + layer.borderWidth = 0; + layer.addSublayer(borderLayer); } } } + +function rectPath(value: string, bounds: Rect): UIBezierPath { + const arr = value.split(/[\s]+/); + const top = cssValueToDevicePixels(arr[0], bounds.top); + const left = cssValueToDevicePixels(arr[1], bounds.left); + const bottom = cssValueToDevicePixels(arr[2], bounds.bottom); + const right = cssValueToDevicePixels(arr[3], bounds.right); + + return UIBezierPath.bezierPathWithRect(CGRectMake(left, top, right - left, bottom - top)).CGPath; +} + +function insetPath(value: string, bounds: Rect): UIBezierPath { + const arr = value.split(/[\s]+/); + + let topString: string; + let rightString: string; + let bottomString: string; + let leftString: string; + if (arr.length === 1) { + topString = rightString = bottomString = leftString = arr[0]; + } + else if (arr.length === 2) { + topString = bottomString = arr[0]; + rightString = leftString = arr[1]; + } + else if (arr.length === 3) { + topString = arr[0]; + rightString = leftString = arr[1]; + bottomString = arr[2]; + } + else if (arr.length === 4) { + topString = arr[0]; + rightString = arr[1]; + bottomString = arr[2]; + leftString = arr[3]; + } + + const top = cssValueToDevicePixels(topString, bounds.bottom); + const right = cssValueToDevicePixels("100%", bounds.right) - cssValueToDevicePixels(rightString, bounds.right); + const bottom = cssValueToDevicePixels("100%", bounds.bottom) - cssValueToDevicePixels(bottomString, bounds.bottom); + const left = cssValueToDevicePixels(leftString, bounds.right); + + return UIBezierPath.bezierPathWithRect(CGRectMake(left, top, right - left, bottom - top)).CGPath; +} + +function circlePath(value: string, bounds: Rect): UIBezierPath { + const arr = value.split(/[\s]+/); + const radius = cssValueToDevicePixels(arr[0], (bounds.right > bounds.bottom ? bounds.bottom : bounds.right) / 2); + const y = cssValueToDevicePixels(arr[2], bounds.bottom); + const x = cssValueToDevicePixels(arr[3], bounds.right); + + return UIBezierPath.bezierPathWithArcCenterRadiusStartAngleEndAngleClockwise(CGPointMake(x, y), radius, 0, 360, true).CGPath; +} + +function ellipsePath(value: string, bounds: Rect): UIBezierPath { + const arr = value.split(/[\s]+/); + + const rX = cssValueToDevicePixels(arr[0], bounds.right); + const rY = cssValueToDevicePixels(arr[1], bounds.bottom); + const cX = cssValueToDevicePixels(arr[3], bounds.right); + const cY = cssValueToDevicePixels(arr[4], bounds.bottom); + + const left = cX - rX; + const top = cY - rY; + const width = rX * 2; + const height = rY * 2; + + return UIBezierPath.bezierPathWithOvalInRect(CGRectMake(left, top, width, height)).CGPath; +} + +function polygonPath(value: string, bounds: Rect): UIBezierPath { + const path = CGPathCreateMutable(); + + let firstPoint: Point; + const arr = value.split(/[,]+/); + for (let i = 0; i < arr.length; i++) { + const xy = arr[i].trim().split(/[\s]+/); + const point: Point = { + x: cssValueToDevicePixels(xy[0], bounds.right), + y: cssValueToDevicePixels(xy[1], bounds.bottom) + }; + + if (!firstPoint) { + firstPoint = point; + CGPathMoveToPoint(path, null, point.x, point.y); + } + + CGPathAddLineToPoint(path, null, point.x, point.y); + } + + CGPathAddLineToPoint(path, null, firstPoint.x, firstPoint.y); + return path; +} \ No newline at end of file diff --git a/tns-core-modules/ui/tab-view/tab-view.android.ts b/tns-core-modules/ui/tab-view/tab-view.android.ts index d315d19e8..24599da4b 100644 --- a/tns-core-modules/ui/tab-view/tab-view.android.ts +++ b/tns-core-modules/ui/tab-view/tab-view.android.ts @@ -3,8 +3,7 @@ import { tabTextColorProperty, tabBackgroundColorProperty, selectedTabTextColorProperty, androidSelectedTabHighlightColorProperty, androidOffscreenTabLimitProperty, fontSizeProperty, fontInternalProperty, View, layout, Color, Font, - traceCategory, traceEnabled, traceWrite, - applyNativeSetters + traceCategory, traceEnabled, traceWrite, initNativeView } from "./tab-view-common" import { textTransformProperty, TextTransform, getTransformedText } from "ui/text-base"; import { fromFileOrResource } from "image-source"; @@ -25,7 +24,7 @@ export class TabViewItem extends TabViewItemBase { public setNativeView(textView: android.widget.TextView): void { this.nativeView = textView; if (textView) { - applyNativeSetters(this); + initNativeView(this); } } diff --git a/tns-core-modules/ui/text-base/text-base.ios.ts b/tns-core-modules/ui/text-base/text-base.ios.ts index 3e30997f0..38d2aa535 100644 --- a/tns-core-modules/ui/text-base/text-base.ios.ts +++ b/tns-core-modules/ui/text-base/text-base.ios.ts @@ -20,12 +20,7 @@ export class TextBase extends TextBaseCommon { //Text get [textProperty.native](): string { - let nativeView = this.nativeView; - if (nativeView instanceof UIButton) { - return nativeView.titleForState(UIControlState.Normal); - } else { - return nativeView.text; - } + return ''; } set [textProperty.native](value: string) { const newValue = (value === undefined || value === null) ? '' : value.toString(); @@ -54,21 +49,22 @@ export class TextBase extends TextBaseCommon { } //Color - get [colorProperty.native](): Color { + get [colorProperty.native](): UIColor { let nativeView = this.nativeView; if (nativeView instanceof UIButton) { - return utils.ios.getColor(nativeView.titleColorForState(UIControlState.Normal)); + return nativeView.titleColorForState(UIControlState.Normal); } else { - return utils.ios.getColor(nativeView.textColor); + return nativeView.textColor; } } - set [colorProperty.native](value: Color) { + set [colorProperty.native](value: Color | UIColor) { + const color = value instanceof Color ? value.ios : value; if (!this.formattedText) { let nativeView = this.nativeView; if (nativeView instanceof UIButton) { - nativeView.setTitleColorForState(value.ios, UIControlState.Normal); + nativeView.setTitleColorForState(color, UIControlState.Normal); } else { - nativeView.textColor = value.ios; + nativeView.textColor = color; } } }