带有 TextKit 和两端对齐文本的 iOS 断字

Igo*_*yuk 5 hyphenation justify ios textkit swift3

今天是个好日子。我在使用带有文本视图的 TextKit 显示带连字符的对齐文本时遇到问题。我试图通过段落样式和 NSLayoutManager 进行断字,但没有预期的结果。段落样式示例:

let paragraph = NSMutableParagraphStyle()
paragraph.alignment = .justified
paragraph.lineBreakMode = .byWordWrapping
paragraph.hyphenationFactor = 0.85 //here goes the black magic :)
Run Code Online (Sandbox Code Playgroud)

问题是没有连字符的对齐文本看起来很糟糕,因为它拉伸了字母(而不是单词)之间的空间。如果连字符有效,一切看起来都很好。但这里有另一个问题 - 断字被应用于具有当前手机首选语言规则的文本。这意味着,如果手机的首选语言是英语并且文本是西里尔文(例如俄语或乌克兰语),则根本不应用连字符,并且会出现文本拉伸问题。下面是这个问题的样子:

没有连字符的拉伸文本

将手机首选语言更改为文本语言会导致本机连字正常工作,并且对齐的文本也可以正确呈现:

精美渲染的文字

所以我的解决方案是使用 NaturalLanguage 框架确定文本语言并将应用程序首选语言更改为该语言。为了确定文本语言,我使用了这个片段:

import NaturalLanguage

extension String {
    func dominantLanguage() -> Locale? {
        let languageRecognizer = NLLanguageRecognizer()
        languageRecognizer.processString(self)

        if let code = languageRecognizer.dominantLanguage?.rawValue {
            let language = Locale.init(identifier: code)
            return language
        } else if let code = languageRecognizer.languageHypotheses(withMaximum: 3).sorted(by: { (arg0, arg1) -> Bool in
            return arg0.value > arg1.value
            }).first?.key.rawValue {
            let language = Locale.init(identifier: code)
            return language
        } else {
            return nil
        }
    }
}

let locale = "qwerty".dominantLanguage()
Run Code Online (Sandbox Code Playgroud)

但是这个解决方案有一个不同的问题:1) 它没有 100% 正确地工作。例如,如果文本以表格开头(如上面的屏幕截图所示),languageRecognizer.dominantLanguage 返回 nil,而 languageHyphoteses 可能返回错误的区域设置。我可能根本不依赖这个。2)每次更改应用程序的首选语言是一种黑客。

我需要找到很好的解决方案来解决这个问题,我想确保在不同的边缘情况下没有任何阻碍。另外,我发现 CoreText 不适合我的其他用途,并且我发现 TextKit 对我来说非常适合,但是我遇到了这个问题,我不知道如何正确解决它。

此外,我发现使用 WebView 和 CSS -webkit-hyphens 可以轻松完成连字符(使用任何文本语言)和对齐文本,但我真的不想像 CoreText 一样深入使用 WebView(不适合用于我的其他应用程序目的)。有没有想法如何使用 TextKit 实现该结果?我正在寻找可靠的解决方案。谢谢你。

den*_*cka 0

使用UITextView相反UILabel是使这项工作正确进行的方法。

hyphenationFactor(作为 NSParagraphStyle 属性或 NSLayoutManager 属性)应该按预期工作。- /sf/answers/1383689331/