Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animating UILabel Font Size Change

I am currently making an application that uses a custom View Controller container. Multiple views are on the screen at one time and when one is tapped, the selected view controller animates to full screen. In doing so, the selected view controllers subviews scale as well (frame, font size, etc.) Though, UILabel's font property is not animatable leading to issues. I have tried multiple solutions but all flat out suck.

The solutions I have tried are:

  1. Take a screenshot of the larger view and animating the change (similar to how Flipboard does)
  2. Animate by using the transform property
  3. Zooming out a UIScrollView and zooming it in when brought to full screen.
  4. Setting adjustsFontSizeToFitWidth to YES and setting the fontSize prior to animation

One has been the best solution so far but I am not satisfied with it.

I'm looking for other suggestions if anyone has any or a UILabel substitue that animates smoothly using [UIView animate..].

Here is a good example that is similar to what I would like my UILabel to do: http://www.cocoawithlove.com/2010/09/zoomingviewcontroller-to-animate-uiview.html

EDIT: This code works

// Load View

self.label = [[UILabel alloc] init];
self.label.text = @"TEXT";
self.label.font = [UIFont boldSystemFontOfSize:20.0];
self.label.backgroundColor = [UIColor clearColor];

[self.label sizeToFit];

[self.view addSubview:self.label];

// Animation

self.label.font = [UIFont boldSystemFontOfSize:80.0];
self.label.transform = CGAffineTransformScale(self.label.transform, .25, .25);
[self.label sizeToFit];

[UIView animateWithDuration:1.0 animations:^{
    self.label.transform = CGAffineTransformScale(self.label.transform, 4.0, 4.0);
    self.label.center = self.view.center;
} completion:^(BOOL finished) {

    self.label.font = [UIFont boldSystemFontOfSize:80.0]; 
    self.label.transform = CGAffineTransformScale(self.label.transform, 1.0, 1.0);

    [self.label sizeToFit];

}];
like image 286
morcutt Avatar asked Jan 24 '13 05:01

morcutt


5 Answers

You can change the size and font of your UILabel with animation like bellow .. here I just put the example of how to change the font of UILabel with transform Animation ..

    yourLabel.font = [UIFont boldSystemFontOfSize:35]; // set font size which you want instead of 35
    yourLabel.transform = CGAffineTransformScale(yourLabel.transform, 0.35, 0.35); 
    [UIView animateWithDuration:1.0 animations:^{
        yourLabel.transform = CGAffineTransformScale(yourLabel.transform, 5, 5);
    }];
like image 72
Paras Joshi Avatar answered Nov 19 '22 00:11

Paras Joshi


For 2017 onwards....

Swift 3.0, 4.0

UIView.animate(withDuration: 0.5) {
     label.transform = CGAffineTransform(scaleX: 1.1, y: 1.1) //Scale label area
 }

Critical:

The critical point to avoid blurring is you must begin with the biggest size, and shrink it. Then expand to "1" when needed.

For quick "pops" (like a highlight animation) it's OK to expand beyond 1 but if you are transitioning between two sizes, make the larger size the "correct" normal one.

like image 34
Chathuranga Silva Avatar answered Nov 19 '22 02:11

Chathuranga Silva


I've created UILabel extension in Swift.

import UIKit

extension UILabel {
    func animate(font: UIFont, duration: TimeInterval) {
        // let oldFrame = frame
        let labelScale = self.font.pointSize / font.pointSize
        self.font = font
        let oldTransform = transform
        transform = transform.scaledBy(x: labelScale, y: labelScale)
        // let newOrigin = frame.origin
        // frame.origin = oldFrame.origin // only for left aligned text
        // frame.origin = CGPoint(x: oldFrame.origin.x + oldFrame.width - frame.width, y: oldFrame.origin.y) // only for right aligned text
        setNeedsUpdateConstraints()
        UIView.animate(withDuration: duration) {
            //L self.frame.origin = newOrigin
            self.transform = oldTransform
            self.layoutIfNeeded()
        }
    }
}

Uncomment lines if the label text is left or right aligned.

like image 27
mixel Avatar answered Nov 19 '22 00:11

mixel


You could also use CATextLayer which has fontSize as an animatable property.

let startFontSize: CGFloat = 20
let endFontSize: CGFloat = 80

let textLayer = CATextLayer()
textLayer.string = "yourText"
textLayer.font = yourLabel.font.fontName as CFTypeRef?
textLayer.fontSize = startFontSize
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.contentsScale = UIScreen.main.scale //for some reason CATextLayer by default only works for 1x screen resolution and needs this line to work properly on 2x, 3x, etc. ...
textLayer.frame = parentView.bounds
parentView.layer.addSublayer(textLayer)

//animation:
let duration: TimeInterval = 1
textLayer.fontSize = endFontSize //because upon completion of the animation CABasicAnimation resets the animated CALayer to its original state (as opposed to changing its properties to the end state of the animation), setting fontSize to endFontSize right BEFORE the animation starts ensures the fontSize doesn't jump back right after the animation.
let fontSizeAnimation = CABasicAnimation(keyPath: "fontSize")
fontSizeAnimation.fromValue = startFontSize
fontSizeAnimation.toValue = endFontSize
fontSizeAnimation.duration = duration
fontSizeAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
textLayer.add(fontSizeAnimation, forKey: nil)

I used it in my project: https://github.com/yinanq/AngelListJobs

This animation keeps the font top left aligned (unlike CGAffineTransformScale scaling the label from center), pro or con depending on your needs. A disadvantage of CATextLayer is that CALayers don't work with autolayout constraint animation (which I happened to need and solved it by making a UIView containing just the CATextLayer and animating its constraints).

like image 19
Yinan Qiu Avatar answered Nov 19 '22 01:11

Yinan Qiu


For those not looking for a transform, but actual value change:

UIView.transition(with: label, duration: 0.25, options: .transitionCrossDissolve, animations: {
    self.label.font = UIFont.systemFont(ofSize: 15)
}) { isFinished in }

enter image description here

like image 12
SirRupertIII Avatar answered Nov 19 '22 01:11

SirRupertIII