11

How can I activate automatic hyphenation in iOS?

I have tried to set the hyphenation factor to 1 in the attributed text options of an UILabel, however I don't get any hyphens though.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Chris
  • 8,031
  • 10
  • 41
  • 67
  • See the correct answer here: http://stackoverflow.com/questions/6968331/ios-automatically-add-hyphen-in-text-field – Nikos M. Oct 31 '13 at 14:44
  • Is there nothing out-of-the-box like in HTML? I don't want to put soft hyphens manually. – Chris Oct 31 '13 at 14:46

3 Answers3

17
  1. The iOS 7 way. Use an UITextView instead of an UILabel. The hyphenationFactor (either as a NSParagraphStyle attribute or as a NSLayoutManager property) should work then (thanks to the new TextKit).
  2. The Web way. Use an UIWebView and the -webkit-hyphens CSS properties.
  3. The Core Text or the hard way. Use the CFStringGetHyphenationLocationBeforeIndex() function that you mentioned in a comment. This function only gives you a hint about where to put hyphens in a string for a specific language. Then you have to break your lines of text yourself using the Core Text functions (like CTLineCreateWithAttributedString() and all). See Getting to Know TextKit (the paragraph called Hyphenation explains the logic of the Core Text process, with no code) and Hyphenation with Core Text on the iPad (gives some code sample, but the website seems to be down right now). It's probably going to be more work than you want!
Guillaume
  • 4,331
  • 2
  • 28
  • 31
  • 3
    `NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init]; paragraph.hyphenationFactor = 1; NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"asdf" attributes:[NSDictionary dictionaryWithObjectsAndKeys:paragraph, NSParagraphStyleAttributeName, nil]];` is also working for UILabel! – Chris Nov 05 '13 at 09:40
  • @Guillaume Have you managed to get (2) UIWebView to handle "-webkit-hyphens" ? It does work in iOS Simulator, but just ignores "hyphens" on iOS devices. – Alexander Smirnov Mar 27 '15 at 10:32
  • when `hyphenationFactor` is set to `1.0` and device's language is set to non-common i.e. Polish or Croatian the hyphenation dash is missing at the end of hyphenated word. – Kubba Mar 07 '16 at 12:02
  • @Kubba did you maybe found a fix for hyphenationFactor not working in languages like Polish and Croatian? I have same problem with Estonian but it works with English and German – Borbea Sep 29 '17 at 21:31
  • @Borbea nope. Bug still hangs in Apple’s Bug Reporter – Kubba Sep 29 '17 at 22:12
  • @Kubba thanks for the fast response. Really bad they still didn't fix that – Borbea Sep 29 '17 at 22:13
  • @Borbea I've double-checked it, updated sample project to Swift 4 and actually It's fixed, at least on iOS 11 – Kubba Oct 02 '17 at 15:16
10

CoreText or TextKit

You need to add "soft hyphenation" to the string. These are "-" which is not visible when rendered, but instead merely queues for CoreText or UITextKit to know how to break up words.

The soft hyphen sign which you should place in the text is:

unichar const kTextDrawingSoftHyphenUniChar = 0x00AD;
NSString * const kTextDrawingSoftHyphenToken = @"­"; // NOTE: UTF-8 soft hyphen!

Example code

NSString *string = @"accessibility tests and frameworks checking";
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
NSString *hyphenatedString = [string softHyphenatedStringWithLocale:locale error:nil];
NSLog(@"%@", hyphenatedString);

Outputs ac-ces-si-bil-i-ty tests and frame-works check-ing


NSString+SoftHyphenation.h

typedef enum {
    NSStringSoftHyphenationErrorNotAvailableForLocale
} NSStringSoftHyphenationError;

extern NSString * const NSStringSoftHyphenationErrorDomain;

@interface NSString (SoftHyphenation)

- (NSString *)softHyphenatedStringWithLocale:(NSLocale *)locale error:(out NSError **)error;

@end

NSString+SoftHyphenation.m

NSString * const NSStringSoftHyphenationErrorDomain = @"NSStringSoftHyphenationErrorDomain";

@implementation NSString (SoftHyphenation)

- (NSError *)hyphen_createOnlyError
{
    NSDictionary *userInfo = @{
                               NSLocalizedDescriptionKey: @"Hyphenation is not available for given locale",
                               NSLocalizedFailureReasonErrorKey: @"Hyphenation is not available for given locale",
                               NSLocalizedRecoverySuggestionErrorKey: @"You could try using a different locale even though it might not be 100% correct"
                               };
    return [NSError errorWithDomain:NSStringSoftHyphenationErrorDomain code:NSStringSoftHyphenationErrorNotAvailableForLocale userInfo:userInfo];
}

- (NSString *)softHyphenatedStringWithLocale:(NSLocale *)locale error:(out NSError **)error
{
    CFLocaleRef localeRef = (__bridge CFLocaleRef)(locale);
    if(!CFStringIsHyphenationAvailableForLocale(localeRef))
    {
        if(error != NULL)
        {
            *error = [self hyphen_createOnlyError];
        }
        return [self copy];
    }
    else
    {
        NSMutableString *string = [self mutableCopy];
        unsigned char hyphenationLocations[string.length];
        memset(hyphenationLocations, 0, string.length);
        CFRange range = CFRangeMake(0, string.length);

        for(int i = 0; i < string.length; i++)
        {
            CFIndex location = CFStringGetHyphenationLocationBeforeIndex((CFStringRef)string,
                                                                         i,
                                                                         range,
                                                                         0,
                                                                         localeRef,
                                                                         NULL);

            if(location >= 0 && location < string.length)
            {
                hyphenationLocations[location] = 1;
            }
        }

        for(int i = string.length - 1; i > 0; i--)
        {
            if(hyphenationLocations[i])
            {
                [string insertString:@"-" atIndex:i];
            }
        }

        if(error != NULL) { *error = nil;}

        return string;
    }
}

@end
hfossli
  • 22,616
  • 10
  • 116
  • 130
  • Very nice, thank you! I am using NSAttributedText having hyphenation factor set to 1. It's also working, but I like your solution more (since its more generic). – Chris Nov 08 '13 at 14:21
  • "These are "-" which is not visible when rendered" Not true. If I set hyphenated string as UITextView's text I still see these dashes – Spail Jan 23 '15 at 14:53
  • @Spail are you 1000 % sure you are using a soft hyphen sign as described in the topmost code example? – hfossli Jan 23 '15 at 15:20
  • 1
    @hfossli my bad. Yeah, it works if you use @"\u00AD" as string which is inserted. Thanks! – Spail Jan 23 '15 at 16:04
  • When using CTFrame hyphens are not displayed :( https://yadi.sk/i/sM3sEAkIqiVN2 While there in the console https://yadi.sk/i/-xjzpyubqiVRU – AlessandroDP Apr 04 '16 at 11:28
4

Swift version:

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.hyphenationFactor = 1
paragraphStyle.alignment = .center

let string = NSAttributedString(string: "wyindywidualizowany indywidualista".uppercased(),
                                attributes: [NSParagraphStyleAttributeName : paragraphStyle])

myLabel.attributedText = string
buxik
  • 2,583
  • 24
  • 31