Can font size of UILabel be changed with smooth animation on iPhone?
Asked Answered
M

5

39

I want a UILabel to swell slightly when selected like in some game menu screens. To get smooth resizing I presume I should put some change to the label's properties in an animation block.

The obvious thing to try is to change the label.font.pointSize property but that's readonly.

Scaling the label's .transform property with CGAffineTransformationMakeScale() makes the text blurry.

Is there some other way to do this?

Murraymurre answered 20/1, 2010 at 3:43 Comment(0)
R
57

Set the font on the UILabel to be the size that you want when it is enlarged. Then scale it down. When you want the label to swell, scale it back up to it's original size.

    messageLabel.font = [UIFont boldSystemFontOfSize:45]; 
    messageLabel.transform = CGAffineTransformScale(messageLabel.transform, 0.25, 0.25); 
    [self.view addSubview:messageLabel]; 
    [UIView animateWithDuration:1.0 animations:^{
        messageLabel.transform = CGAffineTransformScale(messageLabel.transform, 4, 4);
    }];
Rakeoff answered 21/12, 2011 at 16:23 Comment(2)
@Vishal, to revert it I guess you can wait for completion (you can pass a callback block to get notified) and then start another animation.Chukker
This actually scales the label, which means you should set the initial font size to the be as large as possible and then scale down; if you scale up you'll see pixelated text.Overmaster
T
14

UPDATED for Xcode 8 / Swift 3 / iOS 10 SDK.

I've created UILabel extension in Swift. Uncomment commented lines if your label is left aligned.

import UIKit

extension UILabel {
    func animateToFont(_ font: UIFont, withDuration duration: TimeInterval) {
        let oldFont = self.font
        self.font = font
        // let oldOrigin = frame.origin
        let labelScale = oldFont!.pointSize / font.pointSize
        let oldTransform = transform
        transform = transform.scaledBy(x: labelScale, y: labelScale)
        // let newOrigin = frame.origin
        // frame.origin = oldOrigin
        setNeedsUpdateConstraints()
        UIView.animate(withDuration: duration) {
        //    self.frame.origin = newOrigin
            self.transform = oldTransform
            self.layoutIfNeeded()
        }
    }
}

Objective-C version:

@interface UILabel(FontAnimation)

- (void) animateToFont:(UIFont*)font withDuration:(NSTimeInterval) duration;

@end

@implementation UILabel(FontAnimation)

- (void) animateToFont:(UIFont*)font withDuration:(NSTimeInterval) duration {
    UIFont * oldFont = self.font;
    self.font = font;
    // CGPoint oldOrigin = self.frame.origin;
    CGFloat labelScale = oldFont.pointSize / font.pointSize;
    CGAffineTransform oldTransform = self.transform;
    self.transform = CGAffineTransformScale(self.transform, labelScale, labelScale);
    // CGPoint newOrigin = self.frame.origin;
    // self.frame = CGRectMake(oldOrigin.x, oldOrigin.y, self.frame.size.width, self.frame.size.height);
    [self setNeedsUpdateConstraints];
    [UIView animateWithDuration:duration animations: ^{
        // self.frame = CGRectMake(newOrigin.x, newOrigin.y, self.frame.size.width, self.frame.size.height);
        self.transform = oldTransform;
        [self layoutIfNeeded];
    }];
}

@end
Tellurite answered 29/9, 2015 at 20:44 Comment(3)
This is fantastic, but be sure to uncomment let oldTransform = transform because you're using it in the animation without declaring.Bogeyman
@Bogeyman Thx, fixed. Glad to help you!Tellurite
Can you please add the obj-c version to your answer?Vicinity
R
6

If you want animating from fontSize to fontSize you can use CATextLayer class

// create text layer 
let textLayer = CATextLayer()
textLayer.font = UIFont.systemFontOfSize(50)
textLayer.fontSize = 50
textLayer.string = "text"
textLayer.foregroundColor = UIColor.redColor().CGColor
textLayer.backgroundColor = UIColor.blackColor().CGColor
textLayer.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
view.layer.addSublayer(textLayer)

// animation
let animation = CABasicAnimation(keyPath: "fontSize")
animation.toValue = 10
animation.duration = 3
textLayer.layer.addAnimation(animation, forKey: nil)
Risarise answered 3/5, 2016 at 14:22 Comment(0)
J
2

I've just made a solution for this. It's based on CGAffineTransformScale too, but it also has some other tricks up its sleeve and handles all the border cases:

Check it out: https://github.com/ivankovacevic/ARLabel

Jungly answered 16/6, 2013 at 12:0 Comment(0)
D
-1

You can't change the point size of the font, but you can replace the UILabel's font with a new UIFont that uses the new point size you desire.

label.font = [UIFont fontWithName:@"Arial-BoldMT" size:12.0];
// ... some time later
label.font = [UIFont fontWithName:@"Arial-BoldMT" size:14.0];

You'll probably also want to modify the UILabel's frame to accommodate the new point size, especially if you're increasing the point size. Otherwise, your label will get cropped.

Distinguish answered 30/9, 2010 at 4:24 Comment(1)
Not on its own. Scale the UILabel using a transformation like you already mentioned and once the animation is complete, assign the larger UIFont to the UILabel. This should give you the same effect you see when you zoom in and out in mobile Safari. The text is slightly blurry during the pinch/zoom, but once the gesture is complete, the text is rendered using a different font size that matches the current zoom level.Distinguish

© 2022 - 2024 — McMap. All rights reserved.