一、引言
日常开发中使用富文本显示,我们经常会用到的两个方法,坑就在这里面
/// 根据range指定范围添加富文本的某个属性值
open func addAttribute(_ name: NSAttributedString.Key, value: Any, range: NSRange)
/// 根据range指定范围添加富文本的若干个属性值
open func addAttributes(_ attrs: [NSAttributedString.Key : Any] = [:], range: NSRange)
二、发现问题
我们在使用这两个方法的时候,往往会先入为主的认为这两个方法中的参数range是根据字符串的count去计算的,然后如果刚好需求需要设置富文本的字符串包含Emoji表情,你会发现通过这两个方法设置完富文本的属性后,会突然显示出乱码。
三、解决方法
经过反复的思考,发现之前也遇到过这个问题,就是设置包含Emoji表情的富文本会出现乱码,后来发现是range计算出错导致富文本设置属性出现乱码。其实,富文本的属性length是String转为NSString后取NSString的length,所以渲染范围range并不是根据字符串的count属性去计算,而是转NSString后的length计算的,emoji表情的String的count为1,NSString的length却为2,所以只要把字符或者字符串转NSString取length就可以了。
/// Character字符扩展添加计算属性
@inlinable var length: Int {
String(self).length
}
/// String字符串扩展添加计算属性
@inlinable var length: Int {
(self as NSString).length
}
/// 计算range方法
func ranges() -> [NSRange] {
var ranges = [NSRange]()
var index = 0
for char in self {
if char.isValid {
if let range = ranges.last, range.location + range.length >= index {
ranges.removeLast()
ranges.append(NSRange(location: range.location, length: char.length + range.length))
} else {
ranges.append(NSRange(location: index, length: char.length))
}
}
index += char.length
}
return ranges
}