ChatGPT解决这个技术问题 Extra ChatGPT

UILabel 中的动画文本更改

我正在为 UILabel 设置一个新的文本值。目前,新文本看起来很好。但是,我想在新文本出现时添加一些动画。我想知道我可以做些什么来为新文本的外观设置动画。

对于 Swift 5,请参阅 my answer,其中显示了解决问题的 2 种不同方法。

A
Arsen Khachaturyan

我想知道它是否有效,而且效果很好!

Objective-C

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

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

  } completion:nil];

斯威夫特 3, 4, 5

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

请注意,TransitionCrossDissolve 是这项工作的关键。
UIView 动画块中不需要 [weak self]。请参阅stackoverflow.com/a/27019834/511299
请注意,您必须使用示例代码中所述的 transition API,而不是具有几乎相同签名的 animate API。
C
Community

Objective-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"

另请参阅:Animate UILabel text between two numbers?

iOS 10、9、8 中的演示:

https://i.stack.imgur.com/Y8uaD.gif

在 iOS 10 到 8.0 上使用 Xcode 8.2.1 和 7.1、ObjectiveC 进行测试。

► 要下载完整项目,请在 Swift Recipes 中搜索 SO-3073520


当我同时设置两个标签时,它会在模拟器上闪烁。
可能被滥用?我的方法的重点是不使用 2 个标签。您使用单个标签,-addAnimation:forKey 到该标签,然后更改标签的文本。
@ConfusedVorlon,请验证您的陈述。并检查 swiftarchitect.com/recipes/#SO-3073520 上发布的项目。
过去我可能在这方面搞错了。我认为您可以为图层定义一次过渡,然后进行后续更改并获得“自由”淡入淡出。似乎您必须在每次更改时指定淡入淡出。所以 - 如果你每次都调用转换,这在我在 iOS9 上的测试中工作正常。
如果您觉得它不再合适,请删除误导但似乎在 iOS9 中不起作用。谢谢你。
U
Uday Babariya

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

https://i.stack.imgur.com/Y8uaD.gif

► 在 GitHub 上找到此解决方案,在 Swift Recipes 上找到更多详细信息。


您好,我在项目中使用了您的代码,您可能会感兴趣:github.com/goktugyil/CozyLoadingActivity
很好 - 如果你可以使用 MIT 许可证(同一许可证的律师谈话版本),它可以用于商业应用程序......
我不太了解许可证的内容。现在是什么阻止人们在商业应用程序中使用它?
除非在 opensource.org/licenses 中列出,否则许多公司不能使用标准许可证,有些公司只会合并遵守 opensource.org/licenses/MIT 的 Cocoapods。该 MIT 许可证保证您的 Cocoapod 可以被所有人和任何人自由使用。
当前 WTF 许可证的问题在于它不涵盖您的理由:首先,它不声称您是作者(版权),因此不能证明您可以放弃特权。在 MIT 许可证中,您首先声明所有权,然后使用它来放弃权利。如果您希望专业人员利用您的代码并参与您的开源工作,那么您真的应该阅读 MIT。
M
Mapedd

从 iOS4 开始,显然可以用块来完成:

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

不是交叉淡入淡出过渡。
J
Joo Park

这是使这项工作的代码。

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

这不是褪色。这是一个淡出,完全消失,然后淡入。它基本上是一个慢动作闪烁,但它仍然是一个闪烁。
请不要命名你的 UILabel lbl
w
winnie-ru

SwiftArchitect 上述解决方案的 Swift 4.2 版本(效果很好):

    // 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"

M
Muhammad Asyraf

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)

感谢所有提示的家伙。希望这将有助于长期


I
Imanou Petit

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

#1。使用 UIView 的 transition(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。使用 CATransition 和 CALayer 的 add(_: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

两个动画都只像 crossDissolve 一样工作。无论如何,感谢您提供这样一个描述性的答案。
A
Alvin George

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

第一个有效,但第二个只是立即调用完成,无论我通过的持续时间。另一个问题是我在使用第一个解决方案制作动画时无法按下任何按钮。
为了在制作动画时允许交互,我添加了一个选项,options: [.TransitionCrossDissolve, .AllowUserInteraction]
在第一个选项中使用 self.view 会改变整个视图,这意味着只能使用 TransitionCrossDissolve。相反,最好只转换文本:“UIView.transitionWithView(self.sampleLabel,持续时间:1.0 ...”。在我的情况下,它与“...,完成:nil)”效果更好。
i
invisible squirrel

动画的 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"

C
Chris

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

G
Gary Z

这是基于@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";
  } );

R
Roman Aliyev

还有另一种解决方案可以实现这一目标。它被描述为 here。这个想法是通过以下方式继承 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!"

C
Community

如果您想在 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)
}