I have a UITextView that is getting input from the user. I want to replace the input text with attributed text. Currently, I'm using textView(_:shouldChangeTextIn:replacementText:) to set the attributedText property of the text view and then returning false. This seems to work fine except that when adding or deleting the initial character, the cursor is out of sync with the letter that's typed. Sometimes the cursor jumps out before the text has appeared, sometimes the text is deleted before the cursor moves back. Is there any way to keep them in sync?

This doesn't happen all the time so you'll have to keep deleting and re-typing the first character. You can see it on the simulator and a 5s, but on an X it's too fast to see.

Here's an example:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    override func viewDidLoad() {

        let textView = UITextView()
        textView.delegate = self
        textView.frame = {
            var result = view.bounds
            let top: CGFloat = 50.0
            result.size.height -= top
            result.origin.y += top
            return result

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text:     String) -> Bool {
        if text == "\n" {
            return false
        let text = (textView.text as NSString).replacingCharacters(in: range, with: text)
        let attributes: [NSAttributedString.Key: Any] = [
            .font: UIFont.systemFont(ofSize: 17.0, weight: .bold)
        textView.attributedText = NSAttributedString(
            string: text,
            attributes: attributes)
        return false

Related posts

Recent Viewed