本地iOS应用中的连字处理

11

我该如何在iOS中启用自动断字功能?

我尝试在UILabel的属性文本选项中将断字因子设置为1,但是并没有出现任何连字符。


在此处查看正确答案:https://dev59.com/NlrUa4cB1Zd3GeqPfwAI - Nikos M.
有没有像HTML那样的开箱即用的东西?我不想手动添加软连字符。 - Chris
3个回答

17
  1. iOS 7方式。使用UITextView代替UILabel。然后可以使用hyphenationFactor(作为NSParagraphStyle属性或者NSLayoutManager属性)来实现自动分词(感谢新的TextKit)。
  2. Web方式。使用UIWebView-webkit-hyphens CSS属性。
  3. Core Text或者困难方式。使用你在评论中提到的CFStringGetHyphenationLocationBeforeIndex()函数,该函数只能针对特定语言给出字符串中放置连字符的提示信息。然后需要使用Core Text函数(如CTLineCreateWithAttributedString()等)手动将文本行进行断行处理。可以参考Getting to Know TextKit (其中的 Hyphenation 段落介绍了Core Text处理逻辑,但没有代码) 和 iPad上使用Core Text实现连字符 (提供了一些代码示例,但是该网站目前似乎已经无法访问)。这可能比您想要的更费力!

3
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init]; paragraph.hyphenationFactor = 1; NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"asdf" attributes:[NSDictionary dictionaryWithObjectsAndKeys:paragraph, NSParagraphStyleAttributeName, nil]]; 这段代码同样适用于UILabel! - Chris
@Guillaume,你成功让(2)个UIWebView处理“-webkit-hyphens”了吗?它在iOS模拟器中可以工作,但在iOS设备上却忽略了“hyphens”。 - Alexander Smirnov
@Kubba,你是否找到了解决连字符因子在波兰语和克罗地亚语等语言中无法使用的方法?我在使用爱沙尼亚语时也遇到了同样的问题,但对于英语和德语则没有问题。 - Borbea
@Borbea 不是的。Bug仍然存在于苹果的Bug报告系统中。 - Kubba
@Borbea 我已经仔细检查过了,将示例项目更新到Swift 4,并且实际上已经修复了,至少在iOS 11上是这样的。 - Kubba
显示剩余2条评论

10

CoreText或TextKit

您需要在字符串中添加“软连字”。这些是“ - ”,当呈现时不可见,而仅仅是CoreText或UITextKit知道如何分解单词的队列。

您应该放置在文本中的软连字符号是:

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

示例代码

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

输出 可访问性测试和框架检查


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

非常好,谢谢!我正在使用将连字因子设置为1的NSAttributedText。它也可以工作,但我更喜欢您的解决方案(因为它更通用)。 - Chris
这不是真的。如果我将带连字符的字符串设置为UITextView的文本,我仍然可以看到这些破折号。 - Spail
@Spail 你确定你使用的是顶部代码示例中描述的软连字符吗? - hfossli
1
@hfossli 我的错。是的,如果你使用@"\u00AD"作为插入的字符串,它就可以工作了。谢谢! - Spail
在使用CTFrame时,连字符不会显示 :( https://yadi.sk/i/sM3sEAkIqiVN2 同时,在控制台中也没有任何输出 https://yadi.sk/i/-xjzpyubqiVRU - AlessandroDP

4

Swift 版本:

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

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

myLabel.attributedText = string

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接