skip to Main Content

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

Answers


  1. Chosen as BEST ANSWER

    discovered a repo that creates a custom uitextview


  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search