【问题标题】:Emoji support for NSAttributedString attributes (kerning/paragraph style)对 NSAttributedString 属性的表情符号支持(紧缩/段落样式)
【发布时间】:2018-04-03 09:23:43
【问题描述】:

我在UILabel 上使用字距调整属性来显示带有一些自定义字母间距的文本。不幸的是,当我显示用户生成的字符串时,我有时会看到如下内容:

即有时某些表情符号字符不显示。

如果我注释掉字距调整但应用了一些段落样式,我会得到相同类型的错误渲染。

我在文档中找不到任何明确拒绝支持特殊 unicode 字符的内容。我做错了什么还是 iOS 错误?

重现该错误的代码可在此处作为游乐场使用:https://github.com/Bootstragram/Playgrounds/tree/master/LabelWithEmoji.playground

并复制到这里:

//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport

extension NSAttributedString {
    static func kernedSpacedText(_ text: String,
                                    letterSpacing: CGFloat = 0.0,
                                    lineHeight: CGFloat? = nil) -> NSAttributedString {
        // TODO add the font attribute

        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(NSAttributedStringKey.kern,
                                      value: letterSpacing,
                                      range: NSRange(location: 0, length: text.count))

        if let lineHeight = lineHeight {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineSpacing = lineHeight

            attributedString.addAttribute(NSAttributedStringKey.paragraphStyle,
                                          value: paragraphStyle,
                                          range: NSRange(location: 0, length: text.count))
        }

        return attributedString
    }
}

//for familyName in UIFont.familyNames {
//    for fontName in UIFont.fontNames(forFamilyName: familyName) {
//        print(fontName)
//    }
//}

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let myString = "1⚽????????⚾️????????‍♂️????\n2 ???????????? ????"

        let label = UILabel()
        label.frame = CGRect(x: 150, y: 200, width: 200, height: 100)
        label.attributedText = NSAttributedString.kernedSpacedText(myString)
        label.numberOfLines = 0
        label.textColor = .black

        view.addSubview(label)
        self.view = view
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

谢谢。

【问题讨论】:

  • 代码示例和您的屏幕截图是否匹配?它将拇指向上的表情符号变成了这两个?
  • 你的问题可能是这样的:NSRange(location: 0, length: text.count)。 Swift 的字符串计数使用扩展的字形簇。 NSAttributedString 使用 ObjC 的编码,即 UTF-16。尝试将其更改为 text.utf16.count
  • @Larme 他们是。
  • @CodeDifferent:好主意。我没想过检查 ObjC 的编码是什么。它似乎可以解决问题。您为什么不提交您的评论作为答案? :)
  • @CodeDifferent 完全一样,谢谢

标签: ios swift unicode nsattributedstring


【解决方案1】:

TL、DR:

String.count != NSString.length。任何时候看到NSRange,都必须将String 转换为UTF-16:

static func kernedSpacedText(_ text: String,
                                letterSpacing: CGFloat = 0.0,
                                lineHeight: CGFloat? = nil) -> NSAttributedString {
    // TODO add the font attribute

    let attributedString = NSMutableAttributedString(string: text)
    attributedString.addAttribute(NSAttributedStringKey.kern,
                                  value: letterSpacing,
                                  range: NSRange(location: 0, length: text.utf16.count))

    if let lineHeight = lineHeight {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = lineHeight

        attributedString.addAttribute(NSAttributedStringKey.paragraphStyle,
                                      value: paragraphStyle,
                                      range: NSRange(location: 0, length: text.utf16.count))
    }

    return attributedString
}

更长的解释

您的问题是在 Swift 的 String 和 ObjC 的 NSString 之间转换的常见问题。 String 的长度是扩展字形簇的数量;在 ObjC 中,它是编码该字符串所需的 UTF-16 代码点数。

以大拇指字符为例:

let str = "?"
let nsStr = str as NSString

print(str.count)    // 1
print(nsStr.length) // 2

当涉及到国旗表情符号时,事情会变得更加奇怪:

let str = "??"
let nsStr = str as NSString

print(str.count)    // 1
print(nsStr.length) // 4    

尽管这篇文章早在 2003 年就已经写好了,但今天仍然是一本好书: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets.

【讨论】:

  • 这帮助我解决了我在应用 kern 时遇到的 emojis 中断问题
  • 非常感谢您的回答!!修复了一些 emoji 破坏我的文本处理逻辑的令人讨厌的错误 ??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-04
  • 1970-01-01
  • 2018-07-05
  • 2013-08-10
相关资源
最近更新 更多