Tycoon
Tycoon

Reputation: 293

Typewriter effect text animation

I'm trying to create a typewriter animation effect with a UILabel, but can't find any answers. Is the UILabel the correct object to use? I want the text to print to the screen an array of strings like, "Logging in... Opening Folder... Rebooting system.." etc. I should mention that I'm new to coding and I've tried searching the Documentation and API reference but no luck. I'm currently learning SWIFT if thats worth mentioning

Upvotes: 8

Views: 14295

Answers (4)

Gasper J.
Gasper J.

Reputation: 511

my version of the typewriter effect animation using a timer:

    var text = "text"
    
    _ = Timer.scheduledTimer(
        withTimeInterval: 0.1,
        repeats: true
    ) { [weak self] timer in
        let char = text.removeFirst()
        
        self?.yourLabel.text?.append(char.description)
        
        if text.isEmpty {
            timer.invalidate()
        }
    }

Upvotes: 0

Dimas Mendes
Dimas Mendes

Reputation: 2802

Based on this Answer: Letter by letter animation for UILabel?

I've updated it to Swift 4 and solved the CPU animation problem with DispatchWorkItem in order to create a queue.

Swift 4

extension UILabel {
    func setTextWithTypeAnimation(typedText: String, characterDelay: TimeInterval = 5.0) {
        text = ""
        var writingTask: DispatchWorkItem?
        writingTask = DispatchWorkItem { [weak weakSelf = self] in
            for character in typedText {
                DispatchQueue.main.async {
                    weakSelf?.text!.append(character)
                }
                Thread.sleep(forTimeInterval: characterDelay/100)
            }
        }
        
        if let task = writingTask {
            let queue = DispatchQueue(label: "typespeed", qos: DispatchQoS.userInteractive)
            queue.asyncAfter(deadline: .now() + 0.05, execute: task)
        }
    }
    
}

Usage

label.setTextWithTypeAnimation(typedText: text, characterDelay:  10) //less delay is faster

Swift 5

func setTyping(text: String, characterDelay: TimeInterval = 5.0) {
  self.text = ""
    
  let writingTask = DispatchWorkItem { [weak self] in
    text.forEach { char in
      DispatchQueue.main.async {
        self?.text?.append(char)
      }
      Thread.sleep(forTimeInterval: characterDelay/100)
    }
  }
    
  let queue: DispatchQueue = .init(label: "typespeed", qos: .userInteractive)
  queue.asyncAfter(deadline: .now() + 0.05, execute: writingTask)
}

Usage

label.setTyping(text: "Your text")

Upvotes: 16

lcl
lcl

Reputation: 1085

I have written a subclass of UILabel called CLTypingLabel, available on GitHub. This should do what you want.

After installing CocoaPods, add the following like to your Podfile to use it:

pod 'CLTypingLabel'

Sample Code

Change the class of a label from UILabel to CLTypingLabel; enter image description here

@IBOutlet weak var myTypeWriterLabel: CLTypingLabel!

At runtime, set text of the label will trigger animation automatically:

myTypeWriterLabel.text = "This is a demo of typing label animation..."

You can customize time interval between each character:

myTypeWriterLabel.charInterval = 0.08 //optional, default is 0.1

You can pause the typing animation at any time:

myTypeWriterLabel.pauseTyping() //this will pause the typing animation
myTypeWriterLabel.continueTyping() //this will continue paused typing animation

Also there is a sample project that comes with cocoapods

Upvotes: 9

Leo Dabus
Leo Dabus

Reputation: 236498

update: Xcode 7.0 GM • Swift 2.0

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var myTypeWriter: UITextField!
    let myText = Array("Hello World !!!".characters)
    var myCounter = 0
    var timer:NSTimer?
    func fireTimer(){
        timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "typeLetter", userInfo: nil, repeats: true)
    }
    func typeLetter(){
        if myCounter < myText.count {
            myTypeWriter.text = myTypeWriter.text! + String(myText[myCounter])
            let randomInterval = Double((arc4random_uniform(8)+1))/20
            timer?.invalidate()
            timer = NSTimer.scheduledTimerWithTimeInterval(randomInterval, target: self, selector: "typeLetter", userInfo: nil, repeats: false)
        } else {
            timer?.invalidate()
        }
        myCounter++
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        fireTimer()
        // Do any additional setup after loading the view, typically from a nib.
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Upvotes: 9

Related Questions