如何在swift中逐行突出显示UITextView的文本?

时间:2018-03-16 04:22:57

标签: swift loops uitextview

我试图逐行突出显示UITextView中的文字。我想迭代每一行并突出显示那一行供用户查看,然后我想删除突出显示效果以准备下一行。我尝试过但未能创建解决方案,这是我现在最好的机会。

以下是我到目前为止所做的一些工作,目前由于某种原因,它填充了UITextView和“NSBackgroundColor 1101”,我不知道为什么会这样。

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文本并将其放入数组中,方法是将每一行分隔为新的行分隔符。 接下来要做的是创建一个填充了相同文本但是作为可变属性字符串的数组,以开始添加高亮属性。 每次出现突出显示的行时,都会有一个小延迟,直到下一行开始突出显示。如果有人可以帮助或指出我正确的方向开始正确实施这一点,那将极大地帮助,

谢谢!

1 个答案:

答案 0 :(得分:1)

所以你想要这个:

demo

您需要文本视图的内容始终为完整字符串,并突出显示一行,但您的代码将其设置为仅突出显示的行。您的代码还会安排所有突出显示在同一时间(.now() + 0.5)而不是在不同时间发生。

以下是我的建议:

  1. 创建一个范围数组,每行一个范围。

  2. 使用该数组修改文本视图textStorage,方法是根据需要删除并添加.backgroundColor属性,以突出显示和取消突出显示行。

  3. 当您突出显示第n行时,请安排突出显示第n+1行。这有两个好处:如果需要,可以更容易,更有效地取消动画,如果需要,可以更容易地使动画无限重复。

  4. 我使用这个游乐场创建了上面的演示:

    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