请稍侯

在给 nsmutableattr

12 September 2023

在给 NSMutableAttributedString 对象添加属性时,如果文本中含有 Emoji 表情,则会出现乱码的情况

在给 NSMutableAttributedString 对象添加属性时,如果文本中含有 Emoji 表情,则会出现乱码的情况。这是因为 Emoji 表情使用了 Unicode 码点,但是一个 Emoji 表情可能由多个 Unicode 码点组成,当使用 addAttribute(_:value:range:) 方法时,只有第一个码点才会被正确识别,其他码点则会被解析错误,从而导致乱码现象。

要解决这个问题,我们可以使用 NSAttributedString 的 enumerateAttributes(in:options:using:) 方法,逐个遍历文本中所有的 NSAttributedString.Key 属性,并对其进行设置。

以下是一个示例代码:

let str = "Hello 😀 World 🌎"
let attributedString = NSMutableAttributedString(string: str)
attributedString.addAttributes([.foregroundColor: UIColor.red], range: NSRange(location: 0, length: str.count))

attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { (attributes, range, _) in
    var newAttributes = attributes
    // Check if the current attribute is a foreground color
    if let foregroundColor = attributes[NSAttributedString.Key.foregroundColor] as? UIColor {
        // Create a new foreground color with the same color space as the original
        let newForegroundColor = foregroundColor.converted(to: CGColorSpaceCreateDeviceRGB(), intent: .defaultIntent, options: nil)!
        // Update the attribute with the new foreground color
        newAttributes[NSAttributedString.Key.foregroundColor] = newForegroundColor
        // Apply the new attribute to the range
        attributedString.setAttributes(newAttributes, range: range)
    }
}

在这个代码中,我们首先创建了一个包含 Emoji 表情的字符串,并将其转换为 NSMutableAttributedString 对象。然后,我们使用 addAttributes(_:value:range:) 方法添加了前景色属性 foregroundColor。

接着,我们使用 enumerateAttributes(in:options:using:) 方法遍历所有属性,当遇到前景色属性时,我们将其颜色空间转换为设备 RGB 颜色空间,并将其设置为新的前景色属性值,最后再用 setAttributes(_:range:) 方法将新属性应用到文本的相应位置。

或者在构造 NSMutableAttributedString 时传入 attributes 也可以避免这个问题, 如:NSMutableAttributedString(string: str, attributes: attributes)