diff --git a/ui/core/view-common.ts b/ui/core/view-common.ts index e67a36eb8..ddf9d84a8 100644 --- a/ui/core/view-common.ts +++ b/ui/core/view-common.ts @@ -187,6 +187,26 @@ export class View extends proxy.ProxyObject implements definition.View { } // START Style property shortcuts + get borderRadius(): number { + return this.style.borderRadius; + } + set borderRadius(value: number) { + this.style.borderRadius = value; + } + + get borderWidth(): number { + return this.style.borderWidth; + } + set borderWidth(value: number) { + this.style.borderWidth = value; + } + + get borderColor(): color.Color { + return this.style.borderColor; + } + set borderColor(value: color.Color) { + this.style.borderColor = value; + } get color(): color.Color { return this.style.color; diff --git a/ui/core/view.d.ts b/ui/core/view.d.ts index 83d059f9c..be8c9bb3a 100644 --- a/ui/core/view.d.ts +++ b/ui/core/view.d.ts @@ -95,6 +95,21 @@ declare module "ui/core/view" { * A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within. */ export class View extends proxy.ProxyObject { + /** + * Gets or sets the corner radius of the view. + */ + borderRadius: number; + + /** + * Gets or sets the border width of the view. + */ + borderWidth: number; + + /** + * Gets or sets the border color of the view. + */ + borderColor: color.Color; + /** * String value used when hooking to loaded event. */ diff --git a/ui/styling/style.ts b/ui/styling/style.ts index 23edf14c6..4a6682986 100644 --- a/ui/styling/style.ts +++ b/ui/styling/style.ts @@ -45,6 +45,27 @@ export class Style extends observable.DependencyObservable implements styling.St this._setValue(backgroundImageProperty, value, observable.ValueSource.Local); } + get borderColor(): color.Color { + return this._getValue(borderColorProperty); + } + set borderColor(value: color.Color) { + this._setValue(borderColorProperty, value, observable.ValueSource.Local); + } + + get borderWidth(): number { + return this._getValue(borderWidthProperty); + } + set borderWidth(value: number) { + this._setValue(borderWidthProperty, value, observable.ValueSource.Local); + } + + get borderRadius(): number { + return this._getValue(borderRadiusProperty); + } + set borderRadius(value: number) { + this._setValue(borderRadiusProperty, value, observable.ValueSource.Local); + } + get fontSize(): number { return this._getValue(fontSizeProperty); } @@ -385,6 +406,16 @@ function onBackgroundImagePropertyChanged(data: observable.PropertyChangeData) { } } +export var borderColorProperty = new styleProperty.Property("borderColor", "border-color", + new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, undefined, undefined, color.Color.equals), + converters.colorConverter); + +export var borderWidthProperty = new styleProperty.Property("borderWidth", "border-width", + new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isPaddingValid), converters.numberConverter); + +export var borderRadiusProperty = new styleProperty.Property("borderRadius", "border-radius", + new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isPaddingValid), converters.numberConverter); + export var backgroundImageSourceProperty = new styleProperty.Property("backgroundImageSource", "background-image-source", new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, undefined, undefined, undefined)); diff --git a/ui/styling/stylers.android.ts b/ui/styling/stylers.android.ts index 9c12833d5..9fb6f1daf 100644 --- a/ui/styling/stylers.android.ts +++ b/ui/styling/stylers.android.ts @@ -8,11 +8,116 @@ import definition = require("ui/styling"); import stylersCommon = require("ui/styling/stylers-common"); import enums = require("ui/enums"); import utils = require("utils/utils"); +import styleModule = require("ui/styling/style"); +import imageSource = require("image-source"); // merge the exports of the common file with the exports of this file declare var exports; require("utils/module-merge").merge(stylersCommon, exports); +class BorderGradientDrawable extends android.graphics.drawable.GradientDrawable { + private _density = utils.layout.getDisplayDensity(); + + constructor() { + super(); + + return global.__native(this); + } + + private _borderWidth: number; + get borderWidth(): number { + return this._borderWidth; + } + set borderWidth(value: number) { + if (this._borderWidth !== value) { + this._borderWidth = value; + + this.setStroke(this._borderWidth * this._density, this._borderColor); + } + } + + private _cornerRadius: number; + get cornerRadius(): number { + return this._cornerRadius; + } + set cornerRadius(value: number) { + if (this._cornerRadius !== value) { + this._cornerRadius = value; + + this.setCornerRadius(this._cornerRadius); + } + } + + private _borderColor: number; + get borderColor(): number { + return this._borderColor; + } + set borderColor(value: number) { + if (this._borderColor !== value) { + this._borderColor = value; + + this.setStroke(this._borderWidth * this._density, this._borderColor); + } + } + + private _backgroundColor: number; + get backgroundColor(): number { + return this._backgroundColor; + } + set backgroundColor(value: number) { + if (this._backgroundColor !== value) { + this._backgroundColor = value; + + this.setColor(this._backgroundColor); + } + } + + private _bitmap: android.graphics.Bitmap + get bitmap(): android.graphics.Bitmap { + return this._bitmap; + } + set bitmap(value: android.graphics.Bitmap) { + if (this._bitmap !== value) { + this._bitmap = value; + + this.invalidateSelf(); + } + } + + public draw(canvas: android.graphics.Canvas): void { + if (this.bitmap) { + this.setColor(android.graphics.Color.TRANSPARENT); + + var stroke = this._borderWidth * this._density; + canvas.drawBitmap(this.bitmap, stroke, stroke, undefined); + } + super.draw(canvas); + } +} + +function onBorderPropertyChanged(v: view.View) { + if (!this._nativeView) { + return; + } + + var nativeView = v._nativeView; + + var bkg = nativeView.getBackground(); + + if (!(bkg instanceof BorderGradientDrawable)) { + bkg = new BorderGradientDrawable(); + nativeView.setBackground(bkg); + } + + bkg.borderWidth = v.borderWidth; + bkg.cornerRadius = v.borderRadius; + bkg.borderColor = v.borderColor ? v.borderColor.android : android.graphics.Color.TRANSPARENT; + bkg.backgroundColor = v.backgroundColor ? v.backgroundColor.android : android.graphics.Color.TRANSPARENT; + + var value = v.style._getValue(styleModule.backgroundImageSourceProperty); + bkg.bitmap = value ? value.android : undefined; +} + export class DefaultStyler implements definition.stylers.Styler { //Background methods private static setBackgroundProperty(view: view.View, newValue: any) { @@ -62,6 +167,33 @@ export class DefaultStyler implements definition.stylers.Styler { return undefined; } + //Border width methods + private static setBorderWidthProperty(view: view.View, newValue: any) { + onBorderPropertyChanged(view); + } + + private static resetBorderWidthProperty(view: view.View, nativeValue: any) { + view.borderWidth = 0; + } + + //Border color methods + private static setBorderColorProperty(view: view.View, newValue: any) { + onBorderPropertyChanged(view); + } + + private static resetBorderColorProperty(view: view.View, nativeValue: any) { + view.borderColor = undefined; + } + + //Corner radius methods + private static setBorderRadiusProperty(view: view.View, newValue: any) { + onBorderPropertyChanged(view); + } + + private static resetBorderRadiusProperty(view: view.View, nativeValue: any) { + view.borderRadius = 0; + } + //Visibility methods private static setVisibilityProperty(view: view.View, newValue: any) { var androidValue = (newValue === enums.Visibility.visible) ? android.view.View.VISIBLE : android.view.View.GONE; @@ -125,6 +257,18 @@ export class DefaultStyler implements definition.stylers.Styler { style.registerHandler(style.minHeightProperty, new stylersCommon.StylePropertyChangedHandler( DefaultStyler.setMinHeightProperty, DefaultStyler.resetMinHeightProperty)) + + style.registerHandler(style.borderWidthProperty, new stylersCommon.StylePropertyChangedHandler( + DefaultStyler.setBorderWidthProperty, + DefaultStyler.resetBorderWidthProperty)); + + style.registerHandler(style.borderColorProperty, new stylersCommon.StylePropertyChangedHandler( + DefaultStyler.setBorderColorProperty, + DefaultStyler.resetBorderColorProperty)); + + style.registerHandler(style.borderRadiusProperty, new stylersCommon.StylePropertyChangedHandler( + DefaultStyler.setBorderRadiusProperty, + DefaultStyler.resetBorderRadiusProperty)); } } diff --git a/ui/styling/stylers.ios.ts b/ui/styling/stylers.ios.ts index aed8c699b..c5bdefe40 100644 --- a/ui/styling/stylers.ios.ts +++ b/ui/styling/stylers.ios.ts @@ -3,6 +3,7 @@ import style = require("ui/styling/style"); import definition = require("ui/styling"); import stylersCommon = require("ui/styling/stylers-common"); import enums = require("ui/enums"); +import color = require("color"); // merge the exports of the common file with the exports of this file declare var exports; @@ -85,6 +86,45 @@ export class DefaultStyler implements definition.stylers.Styler { } } + //Border width methods + private static setBorderWidthProperty(view: view.View, newValue: any) { + if (view._nativeView instanceof UIView) { + (view._nativeView).layer.borderWidth = newValue; + } + } + + private static resetBorderWidthProperty(view: view.View, nativeValue: any) { + if (view._nativeView instanceof UIView) { + (view._nativeView).layer.borderWidth = nativeValue; + } + } + + //Border color methods + private static setBorderColorProperty(view: view.View, newValue: any) { + if (view._nativeView instanceof UIView && newValue instanceof color.Color) { + (view._nativeView).layer.borderColor = (newValue).ios.CGColor; + } + } + + private static resetBorderColorProperty(view: view.View, nativeValue: any) { + if (view._nativeView instanceof UIView && nativeValue instanceof color.Color) { + (view._nativeView).layer.borderColor = (nativeValue).ios.CGColor; + } + } + + //Border radius methods + private static setBorderRadiusProperty(view: view.View, newValue: any) { + if (view._nativeView instanceof UIView) { + (view._nativeView).layer.cornerRadius = newValue; + } + } + + private static resetBorderRadiusProperty(view: view.View, nativeValue: any) { + if (view._nativeView instanceof UIView) { + (view._nativeView).layer.cornerRadius = nativeValue; + } + } + public static registerHandlers() { style.registerHandler(style.backgroundColorProperty, new stylersCommon.StylePropertyChangedHandler( DefaultStyler.setBackgroundProperty, @@ -103,6 +143,18 @@ export class DefaultStyler implements definition.stylers.Styler { style.registerHandler(style.opacityProperty, new stylersCommon.StylePropertyChangedHandler( DefaultStyler.setOpacityProperty, DefaultStyler.resetOpacityProperty)); + + style.registerHandler(style.borderWidthProperty, new stylersCommon.StylePropertyChangedHandler( + DefaultStyler.setBorderWidthProperty, + DefaultStyler.resetBorderWidthProperty)); + + style.registerHandler(style.borderColorProperty, new stylersCommon.StylePropertyChangedHandler( + DefaultStyler.setBorderColorProperty, + DefaultStyler.resetBorderColorProperty)); + + style.registerHandler(style.borderRadiusProperty, new stylersCommon.StylePropertyChangedHandler( + DefaultStyler.setBorderRadiusProperty, + DefaultStyler.resetBorderRadiusProperty)); } }