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
Animating UILabel Font Size Change
提问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:
我尝试过的解决方案是:
- Take a screenshot of the larger view and animating the change (similar to how Flipboard does)
- Animate by using the transform property
- Zooming out a UIScrollView and zooming it in when brought to full screen.
- Setting adjustsFontSizeToFitWidth to YES and setting the fontSize prior to animation
- 截取较大视图的屏幕截图并为更改设置动画(类似于 Flipboard 的做法)
- 使用 transform 属性制作动画
- 缩小 UIScrollView 并在全屏显示时将其放大。
- 设置 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 UILabel
with animation like bellow .. here I just put the example of how to change the font of UILabel
with transform Animation ..
你可以UILabel
像波纹管一样改变你的动画的大小和字体..在这里我只是举了一个例子来说明如何改变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);
}];
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 UILabel
extension 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 UILabel
to 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
回答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:
由于以下原因,我发现这里的每条建议都不合适:
- They don't actually change the font size.
- They don't play well with frame sizing & auto layout.
- Their interface is non-trivial and/or doesn't play nice inside animation blocks.
- 他们实际上并没有改变字体大小。
- 它们在调整框架大小和自动布局方面表现不佳。
- 他们的界面非常重要和/或在动画块内播放效果不佳。
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 fontSize
property 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 UILabel
or by swizzling the method. I personally swizzle the method, because it lets me keep a generic fontSize
property available to all UILabel
s, 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
可以为所有UILabel
s保留一个通用属性,但这取决于我无法在此处共享的某些库代码。以下是您将如何使用子类化来解决这个问题。
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