如何在 swift 中逐行突出显示 UITextView 的文本?
How to highlight a UITextView's text line by line in swift?
我试图逐行突出显示 UITextView
中的文本。我想遍历每一行并突出显示那一行供用户查看,然后我想删除突出显示效果以为下一行做准备。我已经尝试创建解决方案但未能成功,这是我现在最好的机会。
这是我到目前为止一直在做的一些工作,由于某种原因,它目前用“NSBackgroundColor 1101
”填充了 UITextView
,我不知道为什么会这样。
func highlight() {
let str = "This is\n some placeholder\n text\nwith newlines."
var newStr = NSMutableAttributedString(string: "")
var arr:[String] = str.components(separatedBy: "\n")
var attArr:[NSMutableAttributedString] = []
for i in 0..<arr.count {
attArr.append(NSMutableAttributedString(string: arr[i]))
}
for j in 0..<attArr.count {
let range = NSMakeRange(0, attArr[j].length)
attArr[j].addAttribute(.backgroundColor, value: UIColor.yellow, range: range)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5){
for m in 0..<attArr.count {
newStr = NSMutableAttributedString(string: "\(attArr[m])\n")
self.textView.attributedText = newStr
}
}
attArr[j].removeAttribute(.backgroundColor, range: range)
//remove from texview here
}
}
如您所见,该算法应该剥离 textView
文本并将其放入一个数组中,方法是用新行分隔符分隔每一行。
接下来要做的是创建一个数组,其中填充了相同的文本但作为可变属性字符串开始添加高亮属性。
每次出现突出显示的行时,都会有一个小的延迟,直到下一行开始突出显示。如果有人可以帮助我或为我指明正确的方向以开始正确实施,那将大有帮助,
谢谢!
所以你想要这个:
您需要文本视图的内容始终是完整的字符串,突出显示一行,但您的代码将其设置为仅突出显示的行。您的代码还安排所有高亮显示同时发生 (.now() + 0.5
),而不是在不同时间发生。
这是我的建议:
创建一个范围数组,每行一个范围。
使用该数组修改文本视图的 textStorage
,根据需要删除和添加 .backgroundColor
属性以突出显示和取消突出显示行。
当您突出显示第 n
行时,安排第 n+1
行的突出显示。这有两个好处:如果需要的话,提前取消动画会更容易和更有效,如果需要的话,让动画无限重复会更容易。
我使用这个 playground 创建了上面的演示:
import UIKit
import PlaygroundSupport
let text = "This is\n some placeholder\n text\nwith newlines."
let textView = UITextView(frame: CGRect(x: 0, y:0, width: 200, height: 100))
textView.backgroundColor = .white
textView.text = text
let textStorage = textView.textStorage
// Use NSString here because textStorage expects the kind of ranges returned by NSString,
// not the kind of ranges returned by String.
let storageString = textStorage.string as NSString
var lineRanges = [NSRange]()
storageString.enumerateSubstrings(in: NSMakeRange(0, storageString.length), options: .byLines, using: { (_, lineRange, _, _) in
lineRanges.append(lineRange)
})
func setBackgroundColor(_ color: UIColor?, forLine line: Int) {
if let color = color {
textStorage.addAttribute(.backgroundColor, value: color, range: lineRanges[line])
} else {
textStorage.removeAttribute(.backgroundColor, range: lineRanges[line])
}
}
func scheduleHighlighting(ofLine line: Int) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
if line > 0 { setBackgroundColor(nil, forLine: line - 1) }
guard line < lineRanges.count else { return }
setBackgroundColor(.yellow, forLine: line)
scheduleHighlighting(ofLine: line + 1)
}
}
scheduleHighlighting(ofLine: 0)
PlaygroundPage.current.liveView = textView
我试图逐行突出显示 UITextView
中的文本。我想遍历每一行并突出显示那一行供用户查看,然后我想删除突出显示效果以为下一行做准备。我已经尝试创建解决方案但未能成功,这是我现在最好的机会。
这是我到目前为止一直在做的一些工作,由于某种原因,它目前用“NSBackgroundColor 1101
”填充了 UITextView
,我不知道为什么会这样。
func highlight() {
let str = "This is\n some placeholder\n text\nwith newlines."
var newStr = NSMutableAttributedString(string: "")
var arr:[String] = str.components(separatedBy: "\n")
var attArr:[NSMutableAttributedString] = []
for i in 0..<arr.count {
attArr.append(NSMutableAttributedString(string: arr[i]))
}
for j in 0..<attArr.count {
let range = NSMakeRange(0, attArr[j].length)
attArr[j].addAttribute(.backgroundColor, value: UIColor.yellow, range: range)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5){
for m in 0..<attArr.count {
newStr = NSMutableAttributedString(string: "\(attArr[m])\n")
self.textView.attributedText = newStr
}
}
attArr[j].removeAttribute(.backgroundColor, range: range)
//remove from texview here
}
}
如您所见,该算法应该剥离 textView
文本并将其放入一个数组中,方法是用新行分隔符分隔每一行。
接下来要做的是创建一个数组,其中填充了相同的文本但作为可变属性字符串开始添加高亮属性。
每次出现突出显示的行时,都会有一个小的延迟,直到下一行开始突出显示。如果有人可以帮助我或为我指明正确的方向以开始正确实施,那将大有帮助,
谢谢!
所以你想要这个:
您需要文本视图的内容始终是完整的字符串,突出显示一行,但您的代码将其设置为仅突出显示的行。您的代码还安排所有高亮显示同时发生 (.now() + 0.5
),而不是在不同时间发生。
这是我的建议:
创建一个范围数组,每行一个范围。
使用该数组修改文本视图的
textStorage
,根据需要删除和添加.backgroundColor
属性以突出显示和取消突出显示行。当您突出显示第
n
行时,安排第n+1
行的突出显示。这有两个好处:如果需要的话,提前取消动画会更容易和更有效,如果需要的话,让动画无限重复会更容易。
我使用这个 playground 创建了上面的演示:
import UIKit
import PlaygroundSupport
let text = "This is\n some placeholder\n text\nwith newlines."
let textView = UITextView(frame: CGRect(x: 0, y:0, width: 200, height: 100))
textView.backgroundColor = .white
textView.text = text
let textStorage = textView.textStorage
// Use NSString here because textStorage expects the kind of ranges returned by NSString,
// not the kind of ranges returned by String.
let storageString = textStorage.string as NSString
var lineRanges = [NSRange]()
storageString.enumerateSubstrings(in: NSMakeRange(0, storageString.length), options: .byLines, using: { (_, lineRange, _, _) in
lineRanges.append(lineRange)
})
func setBackgroundColor(_ color: UIColor?, forLine line: Int) {
if let color = color {
textStorage.addAttribute(.backgroundColor, value: color, range: lineRanges[line])
} else {
textStorage.removeAttribute(.backgroundColor, range: lineRanges[line])
}
}
func scheduleHighlighting(ofLine line: Int) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
if line > 0 { setBackgroundColor(nil, forLine: line - 1) }
guard line < lineRanges.count else { return }
setBackgroundColor(.yellow, forLine: line)
scheduleHighlighting(ofLine: line + 1)
}
}
scheduleHighlighting(ofLine: 0)
PlaygroundPage.current.liveView = textView