Letter by Letter Animation for Uilabel

Letter by letter animation for UILabel?

Update for 2018, Swift 4.1:

extension UILabel {

func animate(newText: String, characterDelay: TimeInterval) {

DispatchQueue.main.async {

self.text = ""

for (index, character) in newText.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + characterDelay * Double(index)) {
self.text?.append(character)
}
}
}
}

}

calling it is simple and thread safe:

myLabel.animate(newText: myLabel.text ?? "May the source be with you", characterDelay: 0.3)

@objC, 2012:

Try this prototype function:

- (void)animateLabelShowText:(NSString*)newText characterDelay:(NSTimeInterval)delay
{
[self.myLabel setText:@""];

for (int i=0; i<newText.length; i++)
{
dispatch_async(dispatch_get_main_queue(),
^{
[self.myLabel setText:[NSString stringWithFormat:@"%@%C", self.myLabel.text, [newText characterAtIndex:i]]];
});

[NSThread sleepForTimeInterval:delay];
}
}

and call it in this fashion:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
^{
[self animateLabelShowText:@"Hello Vignesh Kumar!" characterDelay:0.5];
});

Typewriter effect text animation

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

How to animate text color of a UILabel like a progress bar

To achieve it, follow below steps:

  • Create 2 UILabel (trackLabel and progressLabel).
  • trackLabel have blackColor and progressLabel have redColor.
  • Make progressLabel overlap trackLabel, same leading, top and bottom.
  • Give trackLabel full width with text and progressLabel 0 width.
  • Set progressLabel.lineBreakMode = NSLineBreakByClipping;
  • When you need to animate progress, increase width of progressLabel.

For more detail, you can check my demo project.

enter link description here

Animate text change in UILabel

Here is the code to make this work.

[UIView beginAnimations:@"animateText" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:1.0f];
[self.lbl setAlpha:0];
[self.lbl setText:@"New Text";
[self.lbl setAlpha:1];
[UIView commitAnimations];

Animate UILabel text between two numbers?

You can use the automatic transitions. It's working perfectly well :

// Add transition (must be called after myLabel has been displayed)
CATransition *animation = [CATransition animation];
animation.duration = 1.0;
animation.type = kCATransitionFade;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[myLabel.layer addAnimation:animation forKey:@"changeTextTransition"];

// Change the text
myLabel.text = newText;

This code works if myLabel is already displayed. If not myLabel.layer will be nil and the animation will not be added to the object.


in Swift 4 that would be:

let animation: CATransition = CATransition()
animation.duration = 1.0
animation.type = kCATransitionFade
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
myLabel.layer.add(animation, forKey: "changeTextTransition")

Animate text inside label - New word appears as if reading

As @SeyyedParsaNeshaei says, there is another answer that gives a "marquee" type scrolling, however, if what you want (as you say) is one word at a time, consider the following little sketch, which will run in Playground. It basically sets up a timer that changes the text of a UILabel one word at a time.

import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

class MyVC: UIViewController {
var tickTock: Int = 0
var myString = ""
var label: UILabel!
// Following block only needed in Playground.
// Normally you would wire up the label in IB.
{ didSet { self.view.addSubview(self.label) } }

override func viewDidLoad() {
// This next line only necessary in Playground.
// Normally, the view would be set from the StoryBoard
self.view = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 60)))
super.viewDidLoad()
// "1" in the next line is the inter-word interval in seconds.
// Obviously you wouldn't hard-wire this.
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
let words = self.myString.components(separatedBy: " ")
var word = "<Nothing>"
if words.count > 0 {
self.tickTock = self.tickTock % words.count
if !words[self.tickTock].isEmpty {
word = words[self.tickTock]
}
}
self.label?.text = word
self.tickTock += 1
})
}
}
// Playground code to test:
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 60))
label.textColor = .yellow
label.textAlignment = .center
let myVC = MyVC()
myVC.myString = "May the source be with you"
myVC.label = label

PlaygroundPage.current.liveView = myVC.view

To see the animation, select "View>Assistant Editor>Show Assistant Editor" from the Playground menu.

For a fuller solution, you probably want to look at components(separatedBy: CharactersSet) rather than components(separatedBy: String), which I've used - it depends on how you want to present punctuation...

How to animate UILabel text size (and color)

As I mentioned, applying a CGAffineTransform to a UILabel to scale it is frustrating for design-oriented developers, for two reasons.

  1. The transform doesn't account for tracking and font variants. San Francisco (Apple's system font) uses two distinct variants of its font depending on the text size.

iOS automatically applies the most appropriate variant based on the point size and the user's accessibility settings. Adjust tracking—the spacing between letters—appropriately.

SF Pro Text is applied to text 19 points or smaller, while SF Pro Display is applied to text 20 points or larger. Each variant has different "tracking" values — the spacing between letters — for each point size (see: the many tracking values under Font Usage and Tracking).

Unfortunately, CGAffineTransform doesn't set a new pointSize, which would otherwise force a redraw of the view. Applying a transform just scales the rasterized bitmap of the UILabel, which means that fonts and tracking values aren't adaptive. So, if we're scaling our label by 2.0 from 10pt to 20pt, our resulting UILabel at 20pt will still be using SF Pro Text with 12pt tracking, instead of SF Pro Display with 19pt tracking. You can see below that the red label is transformed and hence does not adjust its font.


  1. Transforming a view or layer leads to blurriness. As previously alluded to, Core Graphics doesn't re-render the view, but rather transforms the view's 2D map of pixels. The red label below is clearly blurry.

The Solution

Our best bet is to use CATextLayer instead of UILabel, which Apple says is:

A layer that provides simple text layout and rendering of plain or attributed strings.

The CATextLayer docs list var string: Any?, var font: CFTypeRef?, var fontSize: CGFloat, var foregroundColor: CGColor? and more as properties, which most of the time is all we need. Perfect!

All we need to do is add a CAPropertyAnimation — like CABasicAnimation — to the CATextLayer to animate its properties, like so:

// Create the CATextLayer
let textLayer = CATextLayer()
textLayer.string = "yourText"
textLayer.font = UIFont.systemFont(ofSize: startFontSize)
textLayer.fontSize = startFontSize
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.contentsScale = UIScreen.main.scale
textLayer.frame = view.bounds
view.layer.addSublayer(textLayer)

// Animation
let duration: TimeInterval = 10
textLayer.fontSize = endFontSize
let fontSizeAnimation = CABasicAnimation(keyPath: "fontSize")
fontSizeAnimation.fromValue = startFontSize
fontSizeAnimation.toValue = endFontSize
fontSizeAnimation.duration = duration
textLayer.add(fontSizeAnimation, forKey: nil)

and voila! The black text below is our properly scaled CATextLayer. Sharp and with the correct font variant.

Alt Text

h/t to Yinan for the code: https://stackoverflow.com/a/42047777/4848310. Yinan also discusses how to use CATextLayer with Auto Layout constraint-based animations.


Bonus! This also works for animating text color! Just use the foregroundColor property.



Related Topics



Leave a reply



Submit