Is there a way to animate the text displayed by UILabel
. I want it to show the text value character by character.
Help me with this folks
Is there a way to animate the text displayed by UILabel
. I want it to show the text value character by character.
Help me with this folks
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];
});
Here's @Andrei G.'s answer as a Swift extension:
extension UILabel {
func setTextWithTypeAnimation(typedText: String, characterInterval: NSTimeInterval = 0.25) {
text = ""
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0)) {
for character in typedText.characters {
dispatch_async(dispatch_get_main_queue()) {
self.text = self.text! + String(character)
}
NSThread.sleepForTimeInterval(characterInterval)
}
}
}
}
This might be better.
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *string =@"Risa Kasumi & Yuma Asami";
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:string forKey:@"string"];
[dict setObject:@0 forKey:@"currentCount"];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(typingLabel:) userInfo:dict repeats:YES];
[timer fire];
}
-(void)typingLabel:(NSTimer*)theTimer
{
NSString *theString = [theTimer.userInfo objectForKey:@"string"];
int currentCount = [[theTimer.userInfo objectForKey:@"currentCount"] intValue];
currentCount ++;
NSLog(@"%@", [theString substringToIndex:currentCount]);
[theTimer.userInfo setObject:[NSNumber numberWithInt:currentCount] forKey:@"currentCount"];
if (currentCount > theString.length-1) {
[theTimer invalidate];
}
[self.label setText:[theString substringToIndex:currentCount]];
}
I have write a demo , you can use it , it support ios 3.2 and above
in your .m file
- (void)displayLabelText
{
i--;
if(i<0)
{
[timer invalidate];
}
else
{
[label setText:[NSString stringWithFormat:@"%@",[text substringToIndex:(text.length-i-1)]]];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 60)];
[label setBackgroundColor:[UIColor redColor]];
text = @"12345678";
[label setText:text];
[self.view addSubview:label];
i=label.text.length;
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(displayLabelText) userInfo:nil repeats:YES];
[timer fire];
}
in your .h file
@interface labeltextTestViewController : UIViewController {
UILabel *label;
NSTimer *timer;
NSInteger i;
NSString *text;
}
with the demo , i think you can do in your situation , with a little change the code look like very very ugly because i have to go to have dinner, you can majorization it.
Swift 3 ,Still credit on Andrei G. concept.
extension UILabel{
func setTextWithTypeAnimation(typedText: String, characterInterval: TimeInterval = 0.25) {
text = ""
DispatchQueue.global(qos: .userInteractive).async {
for character in typedText.characters {
DispatchQueue.main.async {
self.text = self.text! + String(character)
}
Thread.sleep(forTimeInterval: characterInterval)
}
}
}
}
I have written a lightweight library specifically for this use case called CLTypingLabel, available on GitHub.
It is efficient, safe and does not sleep any thread. It also provide pause
and continue
interface. Call it anytime you want and it won't break.
After installing CocoaPods, add the following like to your Podfile to use it:
pod 'CLTypingLabel'
Change the class of a label from UILabel to CLTypingLabel;
@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
Update: 2019, swift 5
It works! Just copy paste my answer & see your result
Also create an
@IBOutlet weak var titleLabel: UILabel!
before the viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
titleLabel.text = ""
let titleText = "⚡️Please Vote my answer"
var charIndex = 0.0
for letter in titleText {
Timer.scheduledTimer(withTimeInterval: 0.1 * charIndex, repeats: false) { (timer) in
self.titleLabel.text?.append(letter)
}
charIndex += 1
}
}
SwiftUI + Combine example:
struct TypingText: View {
typealias ConnectablePublisher = Publishers.Autoconnect<Timer.TimerPublisher>
private let text: String
private let timer: ConnectablePublisher
private let alignment: Alignment
@State private var visibleChars: Int = 0
var body: some View {
ZStack(alignment: self.alignment) {
Text(self.text).hidden() // fixes the alignment in position
Text(String(self.text.dropLast(text.count - visibleChars))).onReceive(timer) { _ in
if self.visibleChars < self.text.count {
self.visibleChars += 1
}
}
}
}
init(text: String) {
self.init(text: text, typeInterval: 0.05, alignment: .leading)
}
init(text: String, typeInterval: TimeInterval, alignment: Alignment) {
self.text = text
self.alignment = alignment
self.timer = Timer.TimerPublisher(interval: typeInterval, runLoop: .main, mode: .common).autoconnect()
}
}
There is no default behaviour in UILabel to do this, you could make your own where you add each letter one at a time, based on a timer
I wrote this based on the first answer:
import Foundation
var stopAnimation = false
extension UILabel {
func letterAnimation(newText: NSString?, completion: (finished : Bool) -> Void) {
self.text = ""
if !stopAnimation {
dispatch_async(dispatch_queue_create("backroundQ", nil)) {
if var text = newText {
text = (text as String) + " "
for(var i = 0; i < text.length;i++){
if stopAnimation {
break
}
dispatch_async(dispatch_get_main_queue()) {
let range = NSMakeRange(0,i)
self.text = text.substringWithRange(range)
}
NSThread.sleepForTimeInterval(0.05)
}
completion(finished: true)
}
}
self.text = newText as? String
}
}
}
I know it is too late for the answer but just in case for someone who is looking for the typing animation in UITextView too. I wrote a small library Github for Swift 4. You can set the callback when animation is finished.
@IBOutlet weak var textview:TypingLetterUITextView!
textview.typeText(message, typingSpeedPerChar: 0.1, completeCallback:{
// complete action after finished typing }
Also, I have UILabel extension for typing animation.
label.typeText(message, typingSpeedPerChar: 0.1, didResetContent = true, completeCallback:{
// complete action after finished typing }
Based on @Adam Waite answer. If someone would like to use this with a completion closure.
func setTextWithTypeAnimation(typedText: String, characterInterval: NSTimeInterval = 0.05, completion: () ->()) {
text = ""
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0)) {
for character in typedText.characters {
dispatch_async(dispatch_get_main_queue()) {
self.text = self.text! + String(character)
}
NSThread.sleepForTimeInterval(characterInterval)
}
dispatch_async(dispatch_get_main_queue()) {
completion()
}
}
}
Modifying @Adam Waite's code (nice job, btw) for displaying the text word by word:
func setTextWithWordTypeAnimation(typedText: String, characterInterval: NSTimeInterval = 0.25) {
text = ""
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0)) {
let wordArray = typedText.componentsSeparatedByString(" ")
for word in wordArray {
dispatch_async(dispatch_get_main_queue()) {
self.text = self.text! + word + " "
}
NSThread.sleepForTimeInterval(characterInterval)
}
}
A little improvement to the answer provided by Andrei, not to block the main thread.
- (void)animateLabelShowText:(NSString*)newText characterDelay:(NSTimeInterval)delay
{
[super setText:@""];
NSTimeInterval appliedDelay = delay;
for (int i=0; i<newText.length; i++)
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, appliedDelay * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[super setText:[NSString stringWithFormat:@"%@%c", self.text, [newText characterAtIndex:i]]];
});
appliedDelay += delay;
}
I wrote a small open source lib to do it. I built it with NSAttributedString such that the label won't resize during the animation. It also supports typing sounds and curser animation
Check out here:
© 2022 - 2024 — McMap. All rights reserved.