Lobont Andrei
Lobont Andrei

Reputation: 90

Highlight UITextView text

I have a UITextView in which I would like to add a background to the text (hightlight it). I want everything but new lines to be highlighted. How can I achieve this?

Upvotes: 0

Views: 1009

Answers (1)

Larme
Larme

Reputation: 26016

You can enumerate (enumerate(_:in:option:)) on the NSAttributedString.Key.backgroundColor to find change only when it has a background. Then, you can use a regex, or a while loop with range(of:) to find where they are, and remove the .backgroundColor on them:

With sample code on Playgrounds:

func highlights() -> UITextView {

    let tv = UITextView(frame: CGRect(x: 0, y: 0, width: 300, height: 200))
    tv.backgroundColor = .orange

    let text = "Hello world! How are you today?\nLet's start do some testing.\nAnd this is a long paragraph just to see it to the end of the line."
    let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.boldSystemFont(ofSize: 15.0),
                                                     .backgroundColor: UIColor.systemPink]

    let first = NSAttributedString(string: text, attributes: attributes)
    let second = NSMutableAttributedString(string: text, attributes: attributes)
    guard let regex = try? NSRegularExpression(pattern: "\n", options: []) else { return tv }
    second.enumerateAttribute(.backgroundColor, in: NSRange(location: 0, length: second.length), options: []) { attribute, range, stop in
        guard attribute as? UIColor != nil else { return }
        guard let subrange = Range(range, in: second.string) else { return }
        let substring = String(second.string[subrange])
        let ranges = regex.matches(in: substring, options: [], range: NSRange(location: 0, length: substring.utf16.count))
        ranges.forEach {
            second.removeAttribute(.backgroundColor, range: $0.range)
        }
    }
    let total = NSMutableAttributedString()
    total.append(first)
    total.append(NSAttributedString(string: "\nNormal Text, nothing to see here\n"))
    total.append(second)
    total.append(NSAttributedString(string: "\nNormal Text, nothing to see here\n"))
    tv.attributedText = total
    return tv
}
let tv = highlights()

enter image description here

Side note: I didn't handle the case if you have in the string "\n \n", that might need some changes in the regex pattern. After a quick test, then NSRegularExpression(pattern: "\n(\\s+\n)*", options: []) might do the trick.

Upvotes: 1

Related Questions