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?
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);
}];
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
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)
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
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.