iphone-动画UILabel字体大小更改

我目前正在制作一个使用自定义View Controller容器的应用程序。 一次在屏幕上显示多个视图,而当点击一个视图时,选定的视图控制器会设置为全屏动画。 这样做时,选定的视图控制器子视图也会缩放(框架,字体大小等)。尽管如此,UILabel的font属性无法设置动画,从而导致问题。 我尝试了多种解决方案,但全部失败了。

我尝试过的解决方案是:

  1. 截取较大视图的屏幕截图并为更改添加动画效果(类似于Flipboard的操作)
  2. 通过使用transform属性进行动画处理
  3. 缩小UIScrollView并在全屏显示时将其放大。
  4. 设置将adjustsFontSizeToFitWidth设置为YES,并在动画之前设置fontSize

到目前为止,这是最好的解决方案,但我对此并不满意。

如果有人可以使用[UIView animate ..]进行动画设置,或者有人使用UILabel替换,我正在寻找其他建议。

这是一个很好的示例,类似于我希望UILabel进行的操作:[http://www.cocoawithlove.com/2010/09/zoomingviewcontroller-to-animate-uiview.html]

编辑:此代码有效

// 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];

}];
morcutt asked 2019-10-09T03:23:55Z
8个解决方案
53 votes

您可以使用波纹管等动画来更改UILabel的大小和字体。在这里,我仅举一个如何使用transform Animation ..更改UILabel字体的示例。

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

希望对您有帮助。

Paras Joshi answered 2019-10-09T03:24:13Z
25 votes

从2017年开始...

雨燕3.0,4.0

UIView.animate(withDuration: 0.5) {
     label.transform = CGAffineTransform(scaleX: 1.1, y: 1.1) //Scale label area
 }
Chathuranga Silva answered 2019-10-09T03:24:43Z
21 votes

我已经在Swift中创建了UILabel扩展。

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()
        }
    }
}

如果标签文本左对齐或右对齐,请取消注释行。

mixel answered 2019-10-09T03:25:14Z
12 votes

您也可以使用具有fontSize作为动画属性的CATextLayer。

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)

我在我的项目中使用了它:[https://github.com/yinanq/AngelListJobs]

此动画使字体保持左上对齐(不像CGAffineTransformScale从中心缩放标签),根据您的需要赞成或反对。 CATextLayer的缺点是CALayers不能与自动布局约束动画一起使用(我碰巧需要并通过制作仅包含CATextLayer的UIView并对其约束进行动画处理来解决它)。

Yinan Qiu answered 2019-10-09T03:25:53Z
7 votes

对于想要调整动画方向的人

我为UILabel创建了一个扩展以动画化字体大小变化

extension UILabel {
  func animate(fontSize: CGFloat, duration: TimeInterval) {
    let startTransform = transform
    let oldFrame = frame
    var newFrame = oldFrame
    let scaleRatio = fontSize / font.pointSize

    newFrame.size.width *= scaleRatio
    newFrame.size.height *= scaleRatio
    newFrame.origin.x = oldFrame.origin.x - (newFrame.size.width - oldFrame.size.width) * 0.5
    newFrame.origin.y = oldFrame.origin.y - (newFrame.size.height - oldFrame.size.height) * 0.5
    frame = newFrame

    font = font.withSize(fontSize)

    transform = CGAffineTransform.init(scaleX: 1 / scaleRatio, y: 1 / scaleRatio);
    layoutIfNeeded()

    UIView.animate(withDuration: duration, animations: {
      self.transform = startTransform
      newFrame = self.frame
    }) { (Bool) in
      self.frame = newFrame
    }
  }

如果要调整动画方向,请使用以下方法并放置合适的锚点。

迅速

struct LabelAnimateAnchorPoint {
  // You can add more suitable archon point for your needs
  static let leadingCenterY         = CGPoint.init(x: 0, y: 0.5)
  static let trailingCenterY        = CGPoint.init(x: 1, y: 0.5)
  static let centerXCenterY         = CGPoint.init(x: 0.5, y: 0.5)
  static let leadingTop             = CGPoint.init(x: 0, y: 0)
}

extension UILabel {
  func animate(fontSize: CGFloat, duration: TimeInterval, animateAnchorPoint: CGPoint) {
    let startTransform = transform
    let oldFrame = frame
    var newFrame = oldFrame
    let archorPoint = layer.anchorPoint
    let scaleRatio = fontSize / font.pointSize

    layer.anchorPoint = animateAnchorPoint

    newFrame.size.width *= scaleRatio
    newFrame.size.height *= scaleRatio
    newFrame.origin.x = oldFrame.origin.x - (newFrame.size.width - oldFrame.size.width) * animateAnchorPoint.x
    newFrame.origin.y = oldFrame.origin.y - (newFrame.size.height - oldFrame.size.height) * animateAnchorPoint.y
    frame = newFrame

    font = font.withSize(fontSize)

    transform = CGAffineTransform.init(scaleX: 1 / scaleRatio, y: 1 / scaleRatio);
    layoutIfNeeded()

    UIView.animate(withDuration: duration, animations: {
      self.transform = startTransform
      newFrame = self.frame
    }) { (Bool) in
      self.layer.anchorPoint = archorPoint
      self.frame = newFrame
    }
  }
}

目标C

// You can add more suitable archon point for your needs
#define kLeadingCenterYAnchorPoint         CGPointMake(0.f, .5f)
#define kTrailingCenterYAnchorPoint        CGPointMake(1.f, .5f)
#define kCenterXCenterYAnchorPoint         CGPointMake(.5f, .5f)
#define kLeadingTopAnchorPoint             CGPointMake(0.f, 0.f)

@implementation UILabel (FontSizeAnimating)

- (void)animateWithFontSize:(CGFloat)fontSize duration:(NSTimeInterval)duration animateAnchorPoint:(CGPoint)animateAnchorPoint {
  CGAffineTransform startTransform = self.transform;
  CGRect oldFrame = self.frame;
  __block CGRect newFrame = oldFrame;
  CGPoint archorPoint = self.layer.anchorPoint;
  CGFloat scaleRatio = fontSize / self.font.pointSize;

  self.layer.anchorPoint = animateAnchorPoint;

  newFrame.size.width *= scaleRatio;
  newFrame.size.height *= scaleRatio;
  newFrame.origin.x = oldFrame.origin.x - (newFrame.size.width - oldFrame.size.width) * animateAnchorPoint.x;
  newFrame.origin.y = oldFrame.origin.y - (newFrame.size.height - oldFrame.size.height) * animateAnchorPoint.y;
  self.frame = newFrame;

  self.font = [self.font fontWithSize:fontSize];
  self.transform = CGAffineTransformScale(self.transform, 1.f / scaleRatio, 1.f / scaleRatio);
  [self layoutIfNeeded];

  [UIView animateWithDuration:duration animations:^{
    self.transform = startTransform;
    newFrame = self.frame;
  } completion:^(BOOL finished) {
    self.layer.anchorPoint = archorPoint;
    self.frame = newFrame;
  }];
}

@end

例如,要动画化将标签字体大小更改为30,则持续时间应从中心开始1s,并缩放更大。 只需致电

迅速

YOUR_LABEL.animate(fontSize: 30, duration: 1, animateAnchorPoint: LabelAnimateAnchorPoint.centerXCenterY)

目标C

[YOUR_LABEL animateWithFontSize:30 
                       duration:1 
             animateAnchorPoint:kCenterXCenterYAnchorPoint];
trungduc answered 2019-10-09T03:26:49Z
4 votes

Swift 3.0和Swift 4.0

 UIView.animate(withDuration: 0.5, delay: 0.1, options: .curveLinear, animations: { 

    label.transform = label.transform.scaledBy(x:4,y:4) //Change x,y to get your desired effect. 

    } ) { (completed) in

         //Animation Completed      

    }
Sam Bing answered 2019-10-09T03:27:08Z
1 votes

对于那些不希望转换但实际值发生变化的用户:

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

有文字时,请执行以下操作:

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

(Gif显示不同的字体)

enter image description here

SirRupertIII answered 2019-10-09T03:27:46Z
0 votes

由于以下原因,我发现这里的每个建议都不足够:

  1. 它们实际上并没有更改字体大小。
  2. 它们在框架大小调整和自动布局方面效果不佳。
  3. 他们的界面不平凡,并且/或者在动画块中的播放效果不佳。

为了保留所有这些功能并仍然获得平滑的动画过渡,我将转换方法和字体方法结合在一起。

界面很简单。 只需更新intrinsicContentSize属性,即可更新字体的大小。 在动画块中执行此操作,它将进行动画处理。

@interface UILabel(MPFontSize)

@property(nonatomic) CGFloat fontSize;

@end

至于实现,有简单的方法,有更好的方法。

简单:

@implementation UILabel(MPFontSize)

- (void)setFontSize:(CGFloat)fontSize {

    CGAffineTransform originalTransform = self.transform;
    UIFont *targetFont = [self.font fontWithSize:fontSize];

    [UIView animateWithDuration:0 delay:0 options:0 animations:^{
        self.transform = CGAffineTransformScale( originalTransform,
                fontSize / self.fontSize, fontSize / self.fontSize );
    }                completion:^(BOOL finished) {
        self.transform = originalTransform;
        if (finished)
            self.font = targetFont;
    }];
}

- (CGFloat)fontSize {

    return self.font.pointSize;
};

@end

现在,这样做的问题是布局可能在完成时出现断断续续的情况,因为视图的框架始终根据原始字体调整大小,直到动画完成为止,此时框架更新以适应没有动画的目标字体。

解决这个问题要困难一点,因为我们需要覆盖intrinsicContentSize。您可以通过对UILabel进行子类化或混淆方法来实现。 我个人对此方法感到困惑,因为它使我可以将通用fontSize属性保留给所有UILabels使用,但这取决于我在此处无法共享的某些库代码。 这是使用子类进行此操作的方式。

接口:

@interface AnimatableLabel : UILabel

@property(nonatomic) CGFloat fontSize;

@end

执行:

@interface AnimatableLabel()

@property(nonatomic) UIFont *targetFont;
@property(nonatomic) UIFont *originalFont;

@end

@implementation AnimatableLabel

- (void)setFontSize:(CGFloat)fontSize {

    CGAffineTransform originalTransform = self.transform;
    self.originalFont = self.font;
    self.targetFont = [self.font fontWithSize:fontSize];
    [self invalidateIntrinsicContentSize];

    [UIView animateWithDuration:0 delay:0 options:0 animations:^{
        self.transform = CGAffineTransformScale( originalTransform,
                fontSize / self.fontSize, fontSize / self.fontSize );
    }                completion:^(BOOL finished) {
        self.transform = originalTransform;

        if (self.targetFont) {
            if (finished)
                self.font = self.targetFont;
            self.targetFont = self.originalFont = nil;
            [self invalidateIntrinsicContentSize];
        }
    }];
}

- (CGFloat)fontSize {

    return self.font.pointSize;
};

- (CGSize)intrinsicContentSize {

    @try {
        if (self.targetFont)
            self.font = self.targetFont;
        return self.intrinsicContentSize;
    }
    @finally {
        if (self.originalFont)
            self.font = self.originalFont;
    }
}

@end
lhunath answered 2019-10-09T03:29:16Z
translate from https://stackoverflow.com:/questions/14494566/animating-uilabel-font-size-change