ios 动画 UILabel 字体大小更改

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14494566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:59:20  来源:igfitidea点击:

Animating UILabel Font Size Change

iphoneiosanimationuilabel

提问by morcutt

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.

我目前正在制作一个使用自定义视图控制器容器的应用程序。多个视图同时出现在屏幕上,当点击其中一个时,选定的视图控制器将动画显示为全屏。这样做时,选定的视图控制器子视图也会缩放(框架、字体大小等)。但是,UILabel 的字体属性不是可动画的,从而导致问题。我尝试了多种解决方案,但都很糟糕。

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
  1. 截取较大视图的屏幕截图并为更改设置动画(类似于 Flipboard 的做法)
  2. 使用 transform 属性制作动画
  3. 缩小 UIScrollView 并在全屏显示时将其放大。
  4. 设置 adjustsFontSizeToFitWidth 为 YES 并在动画之前设置 fontSize

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..].

如果有人有任何使用 [UIView animate..] 平滑动画的 UILabel 替代品,我正在寻找其他建议。

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

这是一个很好的例子,类似于我希望我的 UILabel 做的事情: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];

}];

采纳答案by Paras Joshi

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

你可以UILabel像波纹管一样改变你的动画的大小和字体..在这里我只是举了一个例子来说明如何改变UILabelwith 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);
    }];

I hope this helpful to you..

我希望这对你有帮助..

回答by Chathuranga Silva

For 2017 onwards....

从 2017 年开始......

Swift 3.0, 4.0

斯威夫特 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.

避免模​​糊的关键点是你必须从最大的尺寸开始,然后缩小它。然后在需要时扩展到“1”。

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.

对于快速“弹出”(如高亮动画),可以扩展到 1 以上,但如果您在两种尺寸之间转换,请将较大的尺寸设为“正确”的正常尺寸

回答by mixel

I've created UILabelextension in Swift.

我已经UILabel在 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.

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

回答by Yinan Qiu

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

您还可以使用 CATextLayer,它具有 fontSize 作为动画属性。

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

我在我的项目中使用了它: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).

此动画使字体左上角对齐(与 CGAffineTransformScale 从中心缩放标签不同),具体取决于您的需要。CATextLayer 的一个缺点是 CALayer 不能使用自动布局约束动画(我碰巧需要并通过制作只包含 CATextLayer 的 UIView 并为其约束设置动画来解决它)。

回答by trungduc

For someone who wants to adjust direction of animation

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

I have created an extension for UILabelto animate font size change

我创建了一个扩展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
    }
  }


If you want to adjust direction of animation, use below method and put a suitable anchor point.

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

SWIFT

迅速

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

OBJECTIVE-C

目标-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


For example, to animate changing label font size to 30, duration 1s from center and scale bigger. Simply call

例如,将标签字体大小更改为 30,从中心持续 1 秒并缩放更大的动画。只需致电

SWIFT

迅速

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

OBJECTIVE-C

目标-C

[YOUR_LABEL animateWithFontSize:30 
                       duration:1 
             animateAnchorPoint:kCenterXCenterYAnchorPoint];

回答by SirRupertIII

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

在此处输入图片说明

回答by Sam Bing

Swift 3.0 & Swift 4.0

斯威夫特 3.0 和斯威夫特 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      

    }

回答by lhunath

I found each of the suggestions here inadequate for these reasons:

由于以下原因,我发现这里的每条建议都不合适:

  1. They don't actually change the font size.
  2. They don't play well with frame sizing & auto layout.
  3. Their interface is non-trivial and/or doesn't play nice inside animation blocks.
  1. 他们实际上并没有改变字体大小。
  2. 它们在调整框架大小和自动布局方面表现不佳。
  3. 他们的界面非常重要和/或在动画块内播放效果不佳。

In order to retain all of these features & still get a smooth animation transition I've combined the transform approach and the font approach.

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

The interface is simple. Just update the fontSizeproperty and you'll update the font's size. Do this inside an animation block and it'll animate.

界面很简单。只需更新fontSize属性,您就会更新字体的大小。在动画块中执行此操作,它会生成动画。

@interface UILabel(MPFontSize)

@property(nonatomic) CGFloat fontSize;

@end

As for the implementation, there's the simple way, and there's the better way.

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

Simple:

简单的:

@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

Now, the problem with this is that the layout can stutter upon completion, because the view's frame is sized based on the original font all the way until the animation completion, at which point the frame updates to accommodate the target font without animation.

现在,问题是布局在完成时可能会卡顿,因为视图的框架一直基于原始字体调整大小,直到动画完成,此时框架更新以适应没有动画的目标字体。

Fixing this problem is a little harder because we need to override intrinsicContentSize. You can do this either by subclassing UILabelor by swizzling the method. I personally swizzle the method, because it lets me keep a generic fontSizeproperty available to all UILabels, but that depends on some library code I can't share here. Here is how you would go about this using subclassing.

解决这个问题有点困难,因为我们需要覆盖intrinsicContentSize. 你可以通过子类化UILabel或混合方法来做到这一点。我个人对这个方法进行了调整,因为它让我fontSize可以为所有UILabels保留一个通用属性,但这取决于我无法在此处共享的某些库代码。以下是您将如何使用子类化来解决这个问题。

Interface:

界面:

@interface AnimatableLabel : UILabel

@property(nonatomic) CGFloat fontSize;

@end

Implementation:

执行:

@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