UITextView Typing Animation

54 views Asked by At

I have a uitextview with a fixed width and height.

To make the text more digestible, I wanted to perform a character-by-character typing "animation", and was able to get it to work using a Timer object.

My only issue is...when the 1st character is typed for a word that will spill over to the next line, instead of typing that 1st character on the next line, it types on the current line. When the typing hits the end of the uitextview, it's only then that all the previously typed characters of the word are brought over to the next line.

This results in a jerky typing animation, and I'm wondering if it's at all possible to make it smoother by typing the first character on a new line ahead of time. Any guidance would be greatly appreciated!

Here is my current function:

func type(text: String) {

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center
    paragraphStyle.lineBreakMode = .byWordWrapping
    paragraphStyle.paragraphSpacing = 10

    let bodyAttributes = [
        NSAttributedString.Key.foregroundColor: UIColor.black,
        NSAttributedString.Key.paragraphStyle: paragraphStyle,
        NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17)
    ]

    let characters = Array(text)
    var characterIndex = 0

    let attributedString = NSMutableAttributedString()

    Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { [weak self] timer in
        guard let self = self else { return }

        while characters[characterIndex] == " " {
            attributedString.append(NSAttributedString(string: " ", attributes: bodyAttributes))
            textView.attributedText = attributedString

            characterIndex += 1

            if characterIndex == characters.count {
                timer.invalidate()
                return
            }
        }

        let char = String(characters[characterIndex])
       
            attributedString.append(NSAttributedString(string: char, attributes: bodyAttributes))
        
        textView.attributedText = attributedString

        characterIndex += 1

        if characterIndex == characters.count {
            timer.invalidate()
        }
    }
}

Re: Naveet's answer, result: enter image description here

2

There are 2 answers

0
Chris On BEST ANSWER

discovered a repo that creates a custom uitextview

6
Navneet Kaur On
func type(text: String, into textView: UITextView) {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .left
paragraphStyle.lineBreakMode = .byWordWrapping

paragraphStyle.paragraphSpacing = 10

let bodyAttributes: [NSAttributedString.Key: Any] = [
    .foregroundColor: UIColor.black,
    .paragraphStyle: paragraphStyle,
    .font: UIFont.systemFont(ofSize: 17)
]

var characterIndex = 0
let attributedString = NSMutableAttributedString(attributedString: textView.attributedText ?? NSAttributedString())

Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { timer in
    guard characterIndex < text.count else {
        timer.invalidate()
        return
    }
    
    let currentCharacter = text[text.index(text.startIndex, offsetBy: characterIndex)]
    let characterString = String(currentCharacter)
    
    attributedString.append(NSAttributedString(string: characterString, attributes: bodyAttributes))
    textView.attributedText = attributedString
    
    let range = NSRange(location: 0, length: attributedString.length)
    let boundingRect = attributedString.boundingRect(with: CGSize(width: textView.frame.width, height: .greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
    
    if boundingRect.height > textView.bounds.height {
        // If the text has overflowed to the next line, move to the next line
        attributedString.append(NSAttributedString(string: "\n", attributes: bodyAttributes))
        textView.attributedText = attributedString
    }
    
    characterIndex += 1
  }
}

I have updated the code as per requirement please check and let me know if it works. uploading video

Re -

enter image description here