diff --git a/apps/ui-tests-app/css/letter-spacing.xml b/apps/ui-tests-app/css/letter-spacing.xml
new file mode 100644
index 000000000..d1572b6b5
--- /dev/null
+++ b/apps/ui-tests-app/css/letter-spacing.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/button/button.ios.ts b/ui/button/button.ios.ts
index 8f7b1eb6f..788763528 100644
--- a/ui/button/button.ios.ts
+++ b/ui/button/button.ios.ts
@@ -170,20 +170,20 @@ export class ButtonStyler implements style.Styler {
// text-decoration
private static setTextDecorationProperty(view: view.View, newValue: any) {
- utils.ios.setTextDecorationAndTransform(view, newValue, view.style.textTransform);
+ utils.ios.setTextDecorationAndTransform(view, newValue, view.style.textTransform, view.style.letterSpacing);
}
private static resetTextDecorationProperty(view: view.View, nativeValue: any) {
- utils.ios.setTextDecorationAndTransform(view, enums.TextDecoration.none, view.style.textTransform);
+ utils.ios.setTextDecorationAndTransform(view, enums.TextDecoration.none, view.style.textTransform, view.style.letterSpacing);
}
// text-transform
private static setTextTransformProperty(view: view.View, newValue: any) {
- utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, newValue);
+ utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, newValue, view.style.letterSpacing);
}
private static resetTextTransformProperty(view: view.View, nativeValue: any) {
- utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, enums.TextTransform.none);
+ utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, enums.TextTransform.none, view.style.letterSpacing);
}
// white-space
diff --git a/ui/styling/converters.ts b/ui/styling/converters.ts
index 4dbcd68d5..ff595c7a9 100644
--- a/ui/styling/converters.ts
+++ b/ui/styling/converters.ts
@@ -12,6 +12,12 @@ export function fontSizeConverter(value: string): number {
return result;
}
+export function letterSpacingConverter(value: string): number {
+ // TODO: parse different unit types
+ var result: number = parseFloat(value);
+ return result;
+}
+
export function textAlignConverter(value: string): string {
switch (value) {
case enums.TextAlignment.left:
diff --git a/ui/styling/style.d.ts b/ui/styling/style.d.ts
index 38081a3e6..8402f3d89 100644
--- a/ui/styling/style.d.ts
+++ b/ui/styling/style.d.ts
@@ -77,6 +77,7 @@ declare module "ui/styling/style" {
public visibility: string;
public opacity: number;
public whiteSpace: string;
+ public letterSpacing: number;
constructor(parentView: View);
@@ -123,6 +124,7 @@ declare module "ui/styling/style" {
export var textDecorationProperty: styleProperty.Property;
export var textTransformProperty: styleProperty.Property;
export var whiteSpaceProperty: styleProperty.Property;
+ export var letterSpacingProperty: styleProperty.Property;
// Helper property holding most layout related properties available in CSS.
// When layout related properties are set in CSS we chache them and send them to the native view in a single call.
diff --git a/ui/styling/style.ts b/ui/styling/style.ts
index f3cee7ee1..fcdbdff3f 100644
--- a/ui/styling/style.ts
+++ b/ui/styling/style.ts
@@ -417,6 +417,11 @@ function isOpacityValid(value: string): boolean {
return !isNaN(parsedValue) && 0 <= parsedValue && parsedValue <= 1;
}
+function isLetterSpacingValid(value: string): boolean {
+ var parsedValue: number = parseFloat(value);
+ return !isNaN(parsedValue);
+}
+
function isFontWeightValid(value: string): boolean {
return value === enums.FontWeight.normal || value === enums.FontWeight.bold;
}
@@ -768,6 +773,13 @@ export class Style extends DependencyObservable implements styling.Style {
set whiteSpace(value: string) {
this._setValue(whiteSpaceProperty, value);
}
+
+ get letterSpacing(): number {
+ return this._getValue(letterSpacingProperty);
+ }
+ set letterSpacing(value: number) {
+ this._setValue(letterSpacingProperty, value);
+ }
public _updateTextDecoration() {
if (this._getValue(textDecorationProperty) !== enums.TextDecoration.none) {
@@ -1059,6 +1071,9 @@ export var textTransformProperty = new styleProperty.Property("textTransform", "
export var whiteSpaceProperty = new styleProperty.Property("whiteSpace", "white-space",
new PropertyMetadata(undefined, AffectsLayout, undefined, isWhiteSpaceValid), converters.whiteSpaceConverter);
+
+export var letterSpacingProperty = new styleProperty.Property("letterSpacing", "letter-spacing",
+ new PropertyMetadata(Number.NaN, AffectsLayout, undefined, isLetterSpacingValid), converters.letterSpacingConverter);
// Helper property holding most layout related properties available in CSS.
// When layout related properties are set in CSS we chache them and send them to the native view in a single call.
diff --git a/ui/styling/styling.d.ts b/ui/styling/styling.d.ts
index c88983b80..e47395a84 100644
--- a/ui/styling/styling.d.ts
+++ b/ui/styling/styling.d.ts
@@ -201,6 +201,7 @@
textDecoration: string;
textTransform: string;
whiteSpace: string;
+ letterSpacing: number;
//@private
public _beginUpdate();
diff --git a/ui/text-base/text-base-styler.android.ts b/ui/text-base/text-base-styler.android.ts
index af6c505e5..339e88e8b 100644
--- a/ui/text-base/text-base-styler.android.ts
+++ b/ui/text-base/text-base-styler.android.ts
@@ -108,6 +108,23 @@ export class TextBaseStyler implements style.Styler {
utils.ad.setWhiteSpace(view._nativeView, enums.WhiteSpace.normal);
}
+ // letter-spacing
+ private static getLetterSpacingProperty(view: view.View) : any {
+ return view.android.getLetterSpacing ? view.android.getLetterSpacing() : 0;
+ }
+
+ private static setLetterSpacingProperty(view: view.View, newValue: any) {
+ if(view.android.setLetterSpacing) {
+ view.android.setLetterSpacing(utils.layout.toDeviceIndependentPixels(newValue));
+ }
+ }
+
+ private static resetLetterSpacingProperty(view: view.View, nativeValue: any) {
+ if(view.android.setLetterSpacing) {
+ view.android.setLetterSpacing(nativeValue);
+ }
+ }
+
public static registerHandlers() {
style.registerHandler(style.colorProperty, new style.StylePropertyChangedHandler(
TextBaseStyler.setColorProperty,
@@ -136,6 +153,11 @@ export class TextBaseStyler implements style.Styler {
TextBaseStyler.setWhiteSpaceProperty,
TextBaseStyler.resetWhiteSpaceProperty), "TextBase");
+ style.registerHandler(style.letterSpacingProperty, new style.StylePropertyChangedHandler(
+ TextBaseStyler.setLetterSpacingProperty,
+ TextBaseStyler.resetLetterSpacingProperty,
+ TextBaseStyler.getLetterSpacingProperty), "TextBase");
+
// Register the same stylers for Button.
// It also derives from TextView but is not under TextBase in our View hierarchy.
style.registerHandler(style.colorProperty, new style.StylePropertyChangedHandler(
@@ -164,5 +186,10 @@ export class TextBaseStyler implements style.Styler {
style.registerHandler(style.whiteSpaceProperty, new style.StylePropertyChangedHandler(
TextBaseStyler.setWhiteSpaceProperty,
TextBaseStyler.resetWhiteSpaceProperty), "Button");
+
+ style.registerHandler(style.letterSpacingProperty, new style.StylePropertyChangedHandler(
+ TextBaseStyler.setLetterSpacingProperty,
+ TextBaseStyler.resetLetterSpacingProperty,
+ TextBaseStyler.getLetterSpacingProperty), "Button");
}
}
diff --git a/ui/text-base/text-base-styler.ios.ts b/ui/text-base/text-base-styler.ios.ts
index 17fcfe320..0a8650eec 100644
--- a/ui/text-base/text-base-styler.ios.ts
+++ b/ui/text-base/text-base-styler.ios.ts
@@ -38,20 +38,20 @@ export class TextBaseStyler implements style.Styler {
// text-decoration
private static setTextDecorationProperty(view: view.View, newValue: any) {
- utils.ios.setTextDecorationAndTransform(view, newValue, view.style.textTransform);
+ utils.ios.setTextDecorationAndTransform(view, newValue, view.style.textTransform, view.style.letterSpacing);
}
private static resetTextDecorationProperty(view: view.View, nativeValue: any) {
- utils.ios.setTextDecorationAndTransform(view, enums.TextDecoration.none, view.style.textTransform);
+ utils.ios.setTextDecorationAndTransform(view, enums.TextDecoration.none, view.style.textTransform, view.style.letterSpacing);
}
// text-transform
private static setTextTransformProperty(view: view.View, newValue: any) {
- utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, newValue);
+ utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, newValue, view.style.letterSpacing);
}
private static resetTextTransformProperty(view: view.View, nativeValue: any) {
- utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, enums.TextTransform.none);
+ utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, enums.TextTransform.none, view.style.letterSpacing);
}
// white-space
@@ -62,6 +62,15 @@ export class TextBaseStyler implements style.Styler {
private static resetWhiteSpaceProperty(view: view.View, nativeValue: any) {
utils.ios.setWhiteSpace(view._nativeView, enums.WhiteSpace.normal);
}
+
+ // letter-spacing
+ private static setLetterSpacingProperty(view: view.View, newValue: any) {
+ utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, enums.TextTransform.none, newValue);
+ }
+
+ private static resetLetterSpacingProperty(view: view.View, nativeValue: any) {
+ utils.ios.setTextDecorationAndTransform(view, view.style.textDecoration, enums.TextTransform.none, 0);
+ }
// color
private static setColorProperty(view: view.View, newValue: any) {
@@ -106,5 +115,9 @@ export class TextBaseStyler implements style.Styler {
style.registerHandler(style.whiteSpaceProperty, new style.StylePropertyChangedHandler(
TextBaseStyler.setWhiteSpaceProperty,
TextBaseStyler.resetWhiteSpaceProperty), "TextBase");
+
+ style.registerHandler(style.letterSpacingProperty, new style.StylePropertyChangedHandler(
+ TextBaseStyler.setLetterSpacingProperty,
+ TextBaseStyler.resetLetterSpacingProperty), "TextBase");
}
}
diff --git a/utils/utils.d.ts b/utils/utils.d.ts
index ffab8394e..b5381759b 100644
--- a/utils/utils.d.ts
+++ b/utils/utils.d.ts
@@ -145,7 +145,7 @@
* Module with ios specific utilities.
*/
module ios {
- export function setTextDecorationAndTransform(view: any, decoration: string, transform: string);
+ export function setTextDecorationAndTransform(view: any, decoration: string, transform: string, letterSpacing : number);
export function setWhiteSpace(view, value: string, parentView?: any);
export function setTextAlignment(view, value: string);
diff --git a/utils/utils.ios.ts b/utils/utils.ios.ts
index 479ece0b6..652bdb196 100644
--- a/utils/utils.ios.ts
+++ b/utils/utils.ios.ts
@@ -1,4 +1,5 @@
import dts = require("utils/utils");
+import types = require("utils/types");
import common = require("./utils-common");
import {Color} from "color";
import enums = require("ui/enums");
@@ -49,7 +50,9 @@ export module ios {
}
}
- export function setTextDecorationAndTransform(v: any, decoration: string, transform: string) {
+ export function setTextDecorationAndTransform(v: any, decoration: string, transform: string, letterSpacing: number) {
+ let hasLetterSpacing = types.isNumber(letterSpacing) && !isNaN(letterSpacing);
+
if (v.formattedText) {
if (v.style.textDecoration.indexOf(enums.TextDecoration.none) === -1) {
@@ -69,6 +72,22 @@ export module ios {
let span = v.formattedText.spans.getItem(i);
span.text = getTransformedText(v, span.text, transform);
}
+
+ if (hasLetterSpacing) {
+ let attrText;
+ if(v._nativeView instanceof UIButton){
+ attrText = (v._nativeView).attributedTitleForState(UIControlState.UIControlStateNormal);
+ } else {
+ attrText = v._nativeView.attributedText;
+ }
+
+ attrText.addAttributeValueRange(NSKernAttributeName, letterSpacing, { location: 0, length: v._nativeView.attributedText.length });
+
+ if(v._nativeView instanceof UIButton){
+ (v._nativeView).setAttributedTitleForState(attrText, UIControlState.UIControlStateNormal);
+ }
+ }
+
} else {
let source = v.text;
let attributes = new Array();
@@ -76,7 +95,7 @@ export module ios {
var decorationValues = (decoration + "").split(" ");
- if (decorationValues.indexOf(enums.TextDecoration.none) === -1) {
+ if (decorationValues.indexOf(enums.TextDecoration.none) === -1 || hasLetterSpacing) {
let dict = new Map();
if (decorationValues.indexOf(enums.TextDecoration.underline) !== -1) {
@@ -87,6 +106,10 @@ export module ios {
dict.set(NSStrikethroughStyleAttributeName, NSUnderlineStyle.NSUnderlineStyleSingle);
}
+ if (hasLetterSpacing) {
+ dict.set(NSKernAttributeName, letterSpacing);
+ }
+
attributes.push({ attrs: dict, range: NSValue.valueWithRange(range) });
}
@@ -238,7 +261,7 @@ export function openUrl(location: string): boolean {
class UIDocumentInteractionControllerDelegateImpl extends NSObject implements UIDocumentInteractionControllerDelegate {
public static ObjCProtocols = [UIDocumentInteractionControllerDelegate];
- public getViewController() : UIViewController {
+ public getViewController(): UIViewController {
var frame = require("ui/frame");
return frame.topmost().currentPage.ios;
}