在 UILabel 中动画文本更改

我正在将一个新的文本值设置为 UILabel。目前,新文本看起来还不错。但是,我希望在新文本出现时添加一些动画。我想知道我能做些什么来使新文本的外观生动起来。

117748 次浏览

下面是使这个工作的代码。

[UIView beginAnimations:@"animateText" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:1.0f];
[self.lbl setAlpha:0];
[self.lbl setText:@"New Text";
[self.lbl setAlpha:1];
[UIView commitAnimations];

自从 iOS4以来,它显然可以通过块来实现:

[UIView animateWithDuration:1.0
animations:^{
label.alpha = 0.0f;
label.text = newText;
label.alpha = 1.0f;
}];

目标 C

为了实现 没错交叉溶解转换(旧标签淡出 同时新标签淡入) ,您不希望淡出到不可见。会导致 即使文本没有改变,也会出现不必要的闪烁

使用以下方法:

CATransition *animation = [CATransition animation];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = kCATransitionFade;
animation.duration = 0.75;
[aLabel.layer addAnimation:animation forKey:@"kCATransitionFade"];


// This will fade:
aLabel.text = "New"

参见: 在两个数字之间动画 UILabel 文本?

IOS10,9,8的演示:

Blank, then 1 to 5 fade transition


IOS10至8.0上用 Xcode 8.2.1 & 7.1目标 C测试。

扣下载完整的项目,搜索 快速食谱中的 SO-3073520

我想知道它是否有效,而且它完全有效!

目标 C

[UIView transitionWithView:self.label
duration:0.25f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{


self.label.text = rand() % 2 ? @"Nice nice!" : @"Well done!";


} completion:nil];

斯威夫特345

UIView.transition(with: label,
duration: 0.25,
options: .transitionCrossDissolve,
animations: { [weak self] in
self?.label.text = (arc4random()() % 2 == 0) ? "One" : "Two"
}, completion: nil)

Swift 4

淡化 UILabel (或任何 UIView)的正确方法是使用 Core Animation Transition。这不会闪烁,也不会褪色为黑色,如果内容是不变的。

一个可移植且干净的解决方案是在 Swift 中使用 Extension(调用之前更改的可见元素)

// Usage: insert view.fadeTransition right before changing content




extension UIView {
func fadeTransition(_ duration:CFTimeInterval) {
let animation = CATransition()
animation.timingFunction = CAMediaTimingFunction(name:
CAMediaTimingFunctionName.easeInEaseOut)
animation.type = CATransitionType.fade
animation.duration = duration
layer.add(animation, forKey: CATransitionType.fade.rawValue)
}
}

调用看起来像这样:

// This will fade
aLabel.fadeTransition(0.4)
aLabel.text = "text"

Blank, then 1 to 5 fade transition


GitHub上找到这个解决方案,在 快速食谱上找到更多细节。

Swift 2.0:

UIView.transitionWithView(self.view, duration: 1.0, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
self.sampleLabel.text = "Animation Fade1"
}, completion: { (finished: Bool) -> () in
self.sampleLabel.text = "Animation Fade - 34"
})

或者

UIView.animateWithDuration(0.2, animations: {
self.sampleLabel.alpha = 1
}, completion: {
(value: Bool) in
self.sampleLabel.alpha = 0.2
})

如果您想在 Swift中延迟这样做,请尝试这样做:

delay(1.0) {
UIView.transitionWithView(self.introLabel, duration: 0.25, options: [.TransitionCrossDissolve], animations: {
self.yourLabel.text = "2"
}, completion:  { finished in


self.delay(1.0) {
UIView.transitionWithView(self.introLabel, duration: 0.25, options: [.TransitionCrossDissolve], animations: {
self.yourLabel.text = "1"
}, completion:  { finished in


})
}


})
}

使用@matt-https://stackoverflow.com/a/24318861/1982051创建的以下函数:

func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}

在 Swift 3中会变成这样

func delay(_ delay:Double, closure:()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.after(when: when, execute: closure)
}

这是一个基于@SwiftArchitect 代码的 C # UIView 扩展方法。当涉及到自动布局并且控件需要根据标签的文本移动时,这个调用代码使用标签的 Superview 作为转换视图,而不是标签本身。我为该操作添加了一个 lambda 表达式,以使其更加封装。

public static void FadeTransition( this UIView AView, double ADuration, Action AAction )
{
CATransition transition = new CATransition();


transition.Duration = ADuration;
transition.TimingFunction = CAMediaTimingFunction.FromName( CAMediaTimingFunction.Linear );
transition.Type = CATransition.TransitionFade;


AView.Layer.AddAnimation( transition, transition.Type );
AAction();
}

通话代码:

  labelSuperview.FadeTransition( 0.5d, () =>
{
if ( condition )
label.Text = "Value 1";
else
label.Text = "Value 2";
} );

使用 Swift 5,您可以选择以下两个 Playground 代码示例中的一个,以便通过一些交叉溶解动画来动画 UILabel的文本更改。


使用 UIViewtransition(with:duration:options:animations:completion:)类方法

import UIKit
import PlaygroundSupport


class ViewController: UIViewController {


let label = UILabel()


override func viewDidLoad() {
super.viewDidLoad()


label.text = "Car"


view.backgroundColor = .white
view.addSubview(label)


label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true


let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
view.addGestureRecognizer(tapGesture)
}


@objc func toggle(_ sender: UITapGestureRecognizer) {
let animation = {
self.label.text = self.label.text == "Car" ? "Plane" : "Car"
}
UIView.transition(with: label, duration: 2, options: .transitionCrossDissolve, animations: animation, completion: nil)
}


}


let controller = ViewController()
PlaygroundPage.current.liveView = controller

2. 使用 CATransitionCALayeradd(_:forKey:)方法

import UIKit
import PlaygroundSupport


class ViewController: UIViewController {


let label = UILabel()
let animation = CATransition()


override func viewDidLoad() {
super.viewDidLoad()


label.text = "Car"


animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// animation.type = CATransitionType.fade // default is fade
animation.duration = 2


view.backgroundColor = .white
view.addSubview(label)


label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true


let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
view.addGestureRecognizer(tapGesture)
}


@objc func toggle(_ sender: UITapGestureRecognizer) {
label.layer.add(animation, forKey: nil) // The special key kCATransition is automatically used for transition animations
label.text = label.text == "Car" ? "Plane" : "Car"
}


}


let controller = ViewController()
PlaygroundPage.current.liveView = controller

Swift 4.2版本的 SwiftArchitect 解决方案(非常棒) :

    // Usage: insert view.fadeTransition right before changing content


extension UIView {


func fadeTransition(_ duration:CFTimeInterval) {
let animation = CATransition()
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
animation.type = CATransitionType.fade
animation.duration = duration
layer.add(animation, forKey: CATransitionType.fade.rawValue)
}
}

祈求:

    // This will fade


aLabel.fadeTransition(0.4)
aLabel.text = "text"

Swift 4.2解决方案(采用4.0解决方案并更新要编译的新枚举)

extension UIView {
func fadeTransition(_ duration:CFTimeInterval) {
let animation = CATransition()
animation.timingFunction = CAMediaTimingFunction(name:
CAMediaTimingFunctionName.easeInEaseOut)
animation.type = CATransitionType.fade
animation.duration = duration
layer.add(animation, forKey: CATransitionType.fade.rawValue)
}
}


func updateLabel() {
myLabel.fadeTransition(0.4)
myLabel.text = "Hello World"
}

还有一个办法可以实现这一点。它被描述为 给你。这个想法是通过以下方式对 UILabel进行子类化,并覆盖 action(for:forKey:)功能:

class LabelWithAnimatedText: UILabel {
override var text: String? {
didSet {
self.layer.setValue(self.text, forKey: "text")
}
}


override func action(for layer: CALayer, forKey event: String) -> CAAction? {
if event == "text" {
if let action = self.action(for: layer, forKey: "backgroundColor") as? CAAnimation {
let transition = CATransition()
transition.type = kCATransitionFade


//CAMediatiming attributes
transition.beginTime = action.beginTime
transition.duration = action.duration
transition.speed = action.speed
transition.timeOffset = action.timeOffset
transition.repeatCount = action.repeatCount
transition.repeatDuration = action.repeatDuration
transition.autoreverses = action.autoreverses
transition.fillMode = action.fillMode


//CAAnimation attributes
transition.timingFunction = action.timingFunction
transition.delegate = action.delegate


return transition
}
}
return super.action(for: layer, forKey: event)
}
}

用法例子:

// do not forget to set the "Custom Class" IB-property to "LabelWithAnimatedText"
// @IBOutlet weak var myLabel: LabelWithAnimatedText!
// ...


UIView.animate(withDuration: 0.5) {
myLabel.text = "I am animated!"
}
myLabel.text = "I am not animated!"

UILabel 扩展解决方案

extension UILabel{


func animation(typing value:String,duration: Double){
let characters = value.map { $0 }
var index = 0
Timer.scheduledTimer(withTimeInterval: duration, repeats: true, block: { [weak self] timer in
if index < value.count {
let char = characters[index]
self?.text! += "\(char)"
index += 1
} else {
timer.invalidate()
}
})
}




func textWithAnimation(text:String,duration:CFTimeInterval){
fadeTransition(duration)
self.text = text
}


//followed from @Chris and @winnie-ru
func fadeTransition(_ duration:CFTimeInterval) {
let animation = CATransition()
animation.timingFunction = CAMediaTimingFunction(name:
CAMediaTimingFunctionName.easeInEaseOut)
animation.type = CATransitionType.fade
animation.duration = duration
layer.add(animation, forKey: CATransitionType.fade.rawValue)
}


}

通过 简单调用函数

uiLabel.textWithAnimation(text: "text you want to replace", duration: 0.2)

谢谢你们提供的所有建议,希望对我们的长远发展有所帮助

动画的 durationtimingFunction属性可以省略,在这种情况下,它们将分别获取其默认值 0.25.curveEaseInEaseOut

let animation = CATransition()
label.layer.add(animation, forKey: nil)
label.text = "New text"

和写这个是一样的:

let animation = CATransition()
animation.duration = 0.25
animation.timingFunction = .curveEaseInEaseOut
label.layer.add(animation, forKey: nil)
label.text = "New text"