Swift:NSAttributedString 和表情符号
Swift: NSAttributedString & emojis
我使用启用了文本属性编辑的 UITextView
,当文本中有表情符号时,我无法获取属性。
这是我使用的代码:
var textAttributes = [(attributes: [NSAttributedString.Key: Any], range: NSRange)]()
let range = NSRange(location: 0, length: textView.attributedText.length)
textView.attributedText.enumerateAttributes(in: range) { dict, range, _ in
textAttributes.append((attributes: dict, range: range))
}
for attribute in textAttributes {
if let swiftRange = Range(attribute.range, in: textView.text) {
print("NSRange \(attribute.range): \(textView.text![swiftRange])")
} else {
print("NSRange \(attribute.range): cannot convert to Swift range")
}
}
当我尝试使用“示例文本❤️”之类的文本时,输出如下:
NSRange {0, 12}: Sample text
NSRange {12, 1}: cannot convert to Swift range
NSRange {13, 1}: cannot convert to Swift range
如您所见,我无法获取其中包含表情符号的文本。
文本属性由我在文本视图上应用的自定义 NSTextStorage
设置。这是 setAttributes
方法:
override func setAttributes(_ attrs: [NSAttributedString.Key: Any]?, range: NSRange) {
guard (range.location + range.length - 1) < string.count else {
print("Range out of bounds")
return
}
beginEditing()
storage.setAttributes(attrs, range: range)
edited(.editedAttributes, range: range, changeInLength: 0)
endEditing()
}
请注意,在编辑我的文本视图期间,我打印了一些“超出范围”的字样。
有没有办法将 NSRange
转换为有效的 Swift Range
?
使用 NSAttributedString
、NSRange
和 String
时要记住的最重要的事情是 NSAttributedString
(和 NSString
)和 NSRange
基于 UTF-16 编码长度。但是 String
及其 count
是基于实际的字符数。他们不混。
如果您尝试用 someSwiftString.count
创建 NSRange
,您将得到错误的范围。始终使用 someSwiftString.utf16.count
.
在您的特定情况下,由于 NSRange
中的长度错误,您正在将 ❤️ 字符的属性应用到一半,这会导致您看到的错误。
并且在您发布的代码中,您需要更改:
guard (range.location + range.length - 1) < string.count else {
至:
guard (range.location + range.length - 1) < string.utf16.count else {
出于与上述相同的原因。
我使用启用了文本属性编辑的 UITextView
,当文本中有表情符号时,我无法获取属性。
这是我使用的代码:
var textAttributes = [(attributes: [NSAttributedString.Key: Any], range: NSRange)]()
let range = NSRange(location: 0, length: textView.attributedText.length)
textView.attributedText.enumerateAttributes(in: range) { dict, range, _ in
textAttributes.append((attributes: dict, range: range))
}
for attribute in textAttributes {
if let swiftRange = Range(attribute.range, in: textView.text) {
print("NSRange \(attribute.range): \(textView.text![swiftRange])")
} else {
print("NSRange \(attribute.range): cannot convert to Swift range")
}
}
当我尝试使用“示例文本❤️”之类的文本时,输出如下:
NSRange {0, 12}: Sample text
NSRange {12, 1}: cannot convert to Swift range
NSRange {13, 1}: cannot convert to Swift range
如您所见,我无法获取其中包含表情符号的文本。
文本属性由我在文本视图上应用的自定义 NSTextStorage
设置。这是 setAttributes
方法:
override func setAttributes(_ attrs: [NSAttributedString.Key: Any]?, range: NSRange) {
guard (range.location + range.length - 1) < string.count else {
print("Range out of bounds")
return
}
beginEditing()
storage.setAttributes(attrs, range: range)
edited(.editedAttributes, range: range, changeInLength: 0)
endEditing()
}
请注意,在编辑我的文本视图期间,我打印了一些“超出范围”的字样。
有没有办法将 NSRange
转换为有效的 Swift Range
?
使用 NSAttributedString
、NSRange
和 String
时要记住的最重要的事情是 NSAttributedString
(和 NSString
)和 NSRange
基于 UTF-16 编码长度。但是 String
及其 count
是基于实际的字符数。他们不混。
如果您尝试用 someSwiftString.count
创建 NSRange
,您将得到错误的范围。始终使用 someSwiftString.utf16.count
.
在您的特定情况下,由于 NSRange
中的长度错误,您正在将 ❤️ 字符的属性应用到一半,这会导致您看到的错误。
并且在您发布的代码中,您需要更改:
guard (range.location + range.length - 1) < string.count else {
至:
guard (range.location + range.length - 1) < string.utf16.count else {
出于与上述相同的原因。