Hyphenation in iOS

uiux

#1

Hello!

I’m trying to enable iOS hyphenation for my labels in NativeScript.
Unfortunately not too successful.

Here’s what I’ve tried:

    <Label (loaded)="onLabelLoaded($event)"></Label>
    onLabelLoaded(args) {
        const label = args.object as Label;
        const paragraphStyle = NSMutableParagraphStyle.alloc().init();
        const attributes = new Map();

        paragraphStyle.hyphenationFactor = 1.0;
        paragraphStyle.lineBreakMode = NSLineBreakMode.NSLineBreakByWordWrapping;
        attributes.set(NSParagraphStyleAttributeName, paragraphStyle);

        const attributedString = NSMutableAttributedString.alloc().initWithStringAttributes("Schulmuseum Lohr am Main", attributes);

        label.ios.attributedText = attributedString;
    }

You might as well have a look at my playground: https://play.nativescript.org/?template=play-ng&id=hsv7zD&v=2

Basically I tried to implement the suggested solution here: https://stackoverflow.com/a/19414663/7500705

Has anyone ever got something like this to work?
Maybe using a angular pipe or even extending the capabilities of NativeScript so that we could use CSS?

Here’s a screenshot showing the issue with the above code.
As you can see hyphenation and line break mode are not really working…


#2

I have just got hyphenation to work. Anyways I’m still looking for help on how to apply that to labels that maybe already got some styling from CSS in place. For example line height styling…

Here’s the working version: https://play.nativescript.org/?template=play-ng&id=hsv7zD&v=3


#3

Try this one,


import { isIOS } from "platform";
import { TextBase } from "ui/text-base";

declare var NSParagraphStyleAttributeName, NSMutableParagraphStyle;

if (isIOS) {
    (<any>TextBase.prototype).originalSetTextDecorationAndTransform = (<any>TextBase.prototype).setTextDecorationAndTransform;
    (<any>TextBase.prototype).setTextDecorationAndTransform = function () {
        (<any>TextBase.prototype).originalSetTextDecorationAndTransform.call(this);
        const attributedText = this.nativeViewProtected.attributedText;
        if (attributedText) {
            const paragraphStyle = NSMutableParagraphStyle.alloc().init();
            paragraphStyle.hyphenationFactor = 1;
            attributedText.addAttributeValueRange(NSParagraphStyleAttributeName, paragraphStyle, { location: 0, length: attributedText.length });
        }
    };
}

Note: Might need little more tweaks if you use formatted text.


#4

Thank you @manojdcoder I’ve also made some progress with formatted text: https://play.nativescript.org/?template=play-ng&id=hsv7zD&v=5

I’ll try to implement this in a way that it is plug and play and flexible enough. Once I end up with a good solution I’ll post it here.


#5

I’ve got a good solution now I think:

Just put the following code into main.ts before bootstrapping:

/**
 * Allow hyphenation using CSS or HTML attributes.
 *
 * CSS example: Label { hyphens: auto; }
 * HTML example: <Label hyphens="auto" textWrap="true" text="Lorem ipsum dolor sit amet."></Label>
 */
import { isIOS } from "platform";
import { TextBase } from "ui/text-base";

declare var NSParagraphStyleAttributeName, NSMutableParagraphStyle;
declare const NSMutableAttributedString: any;
declare const NSLineBreakMode: any;
declare const interop: any;

if (isIOS) {
    (<any>TextBase.prototype).originalSetTextDecorationAndTransform = (<any>TextBase.prototype).setTextDecorationAndTransform;
    (<any>TextBase.prototype).setTextDecorationAndTransform = function () {
        (<any>TextBase.prototype).originalSetTextDecorationAndTransform.call(this);

        if (this.hyphens === "auto") {
            const attributedText = this.nativeViewProtected.attributedText;
            const range = { location: 0, length: attributedText.length };
            const rangeReference = new interop.Reference(range);
            const attributes = attributedText.attributesAtIndexEffectiveRange(0, rangeReference);
            const paragraphStyle = attributes.objectForKey(NSParagraphStyleAttributeName).mutableCopy();

            paragraphStyle.hyphenationFactor = 1.0;
            attributedText.addAttributeValueRange(NSParagraphStyleAttributeName, paragraphStyle, range);
        }
    };
}

Or have a look at the playground: https://play.nativescript.org/?template=play-ng&id=hsv7zD&v=7


#6

Well unfortunately my solution does not play nice with asynchronous data:

Any ideas on how to solve this?


#7

Okay, got it fixed for asynchronous data as well.

Just put the following code into main.ts before bootstrapping:

/**
 * Allow hyphenation using CSS or HTML attributes.
 *
 * CSS example: Label { hyphens: auto; }
 * HTML example: <Label hyphens="auto" textWrap="true" text="Lorem ipsum dolor sit amet."></Label>
 */
import { isIOS } from "platform";
import { TextBase } from "ui/text-base";

declare var NSParagraphStyleAttributeName, NSMutableParagraphStyle, NSMakeRange, NSMutableAttributedString;

if (isIOS) {
    (<any>TextBase.prototype).originalSetTextDecorationAndTransform = (<any>TextBase.prototype).setTextDecorationAndTransform;
    (<any>TextBase.prototype).setTextDecorationAndTransform = function () {
        (<any>TextBase.prototype).originalSetTextDecorationAndTransform.call(this);

        if (this.nativeViewProtected.attributedText.length && this.hyphens === "auto") {
            const attributedText = this.nativeViewProtected.attributedText;
            const range = NSMakeRange(0, attributedText.length);
            const attributes = attributedText.attributesAtIndexEffectiveRange(0, range);
            const paragraphStyle = attributes.objectForKey(NSParagraphStyleAttributeName).mutableCopy();

            paragraphStyle.hyphenationFactor = 1.0;
            attributedText.addAttributeValueRange(NSParagraphStyleAttributeName, paragraphStyle, range);
        }
    };
}

Or have a look at the playground: https://play.nativescript.org/?template=play-ng&id=hsv7zD&v=9