一涡上、引言
日常開發(fā)中使用富文本顯示,我們經(jīng)常會用到的兩個方法,坑就在這里面??
/// 根據(jù)range指定范圍添加富文本的某個屬性值
open func addAttribute(_ name: NSAttributedString.Key, value: Any, range: NSRange)
/// 根據(jù)range指定范圍添加富文本的若干個屬性值
open func addAttributes(_ attrs: [NSAttributedString.Key : Any] = [:], range: NSRange)
二衙耕、發(fā)現(xiàn)問題
我們在使用這兩個方法的時候,往往會先入為主的認為這兩個方法中的參數(shù)range是根據(jù)字符串的count去計算的勺远,然后如果剛好需求需要設置富文本的字符串包含Emoji表情橙喘,你會發(fā)現(xiàn)通過這兩個方法設置完富文本的屬性后,會突然顯示出亂碼胶逢。
三厅瞎、解決方法
經(jīng)過反復的思考,發(fā)現(xiàn)之前也遇到過這個問題宪塔,就是設置包含Emoji表情的富文本會出現(xiàn)亂碼磁奖,后來發(fā)現(xiàn)是range計算出錯導致富文本設置屬性出現(xiàn)亂碼。其實某筐,富文本的屬性length是String轉(zhuǎn)為NSString后取NSString的length比搭,所以渲染范圍range并不是根據(jù)字符串的count屬性去計算,而是轉(zhuǎn)NSString后的length計算的,emoji表情的String的count為1身诺,NSString的length卻為2蜜托,所以只要把字符或者字符串轉(zhuǎn)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
}