【问题标题】:Smoothly pause a repeating UIView block animation on alpha before another animation在另一个动画之前在 alpha 上平滑暂停重复的 UIView 块动画
【发布时间】:2020-01-06 20:58:15
【问题描述】:

我已经阅读了许多 Stack Overflow 问题以寻找解决方案,但我找不到一个以适用于 iOS 13 的方式解决此特定问题的问题。

我有一个标签,一旦我的视图控制器加载,我想重复脉冲(如缓慢的、逐渐消失的闪烁)。

当需要从视图中转换时,只需按一下按钮,我想在脉冲标签当前具有的任何 alpha 处停止脉冲,然后将其与其他 UI 元素一起从那里淡出。

过去,我会为这个重复动画使用UIViewPropertyAnimator,然后在点击按钮后暂停动画,但从 iOS 13 开始,UIView.setAnimationRepeatCount(.greatestFiniteMagnitude)UIView.setAnimationRepeatAutoreverses(true) 已弃用,(我认为) 使我无法使用属性动画器构建我的脉冲动画。

这是我的示例代码:

import UIKit

class ViewController: UIViewController {

    private lazy var pulsingLabel: UILabel = {
        let label = UILabel()
        label.text = "I am pulsing"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    private lazy var stopButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Stop Pulsing",
                        for: .normal)
        button.addTarget(self,
                         action: #selector(fadeEverythingOut),
                         for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(pulsingLabel)
        view.addSubview(stopButton)

        pulsingLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        pulsingLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        stopButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        stopButton.firstBaselineAnchor.constraint(equalToSystemSpacingBelow: pulsingLabel.lastBaselineAnchor,
                                                  multiplier: 4).isActive = true

        startRepeatingAnimation()
    }

    private func startRepeatingAnimation() {
        UIView.animate(withDuration: 1,
                       delay: 0,
                       options: [.repeat, .autoreverse, .curveEaseInOut],
                       animations: {
            self.pulsingLabel.alpha = 0
        })
    }

    @objc
    private func fadeEverythingOut() {

        pulsingLabel.layer.removeAllAnimations()

        UIView.animate(withDuration: 2.0,
                       animations: {
            self.pulsingLabel.alpha = 0
        })
    }
}

在本例中,我调用 pulsingLabel.layer.removeAllAnimations() 来停止动画,但这不是一个可接受的解决方案,因为标签在被调用时会立即消失。

我还尝试了一些奇怪的东西,比如将那条线夹在 UIView.setAnimationsEnabled(false)UIView.setAnimationsEnabled(true) 之间,但没有奏效。

我还尝试在调用 pulsingLabel.layer.removeAllAnimations() 之前保存 pulsingLabel 的 alpha,然后在之后再次设置它,但对于 pulsingLabel.alpha,我总是得到 0 的值。

我是否因为放弃 UIViewPropertyAnimator 而遗漏了一些东西,即使在 UIView 上使用了已弃用的功能,我仍然可以让它重复?或者我可能需要在不同的层或以某种方式调用.layer.removeAllAnimations()

任何想法都将不胜感激,因为我非常关心在我的应用中获得这些精细的细节!

【问题讨论】:

  • 你不能。 UiView 动画块立即应用该属性,但 iOS 只是为更改设置动画。您需要通过某种后台计时器线程运行。
  • @GeneCode 好的,谢谢。您能否提供一个使用“通过某种后台计时器线程运行”的方法的答案?

标签: ios swift uiview uiviewanimation


【解决方案1】:

我没有看到你在寻找快速的答案,但我现在只知道 ObjC。所以这是计时器的解决方案(虽然在 ObjC 中很抱歉):

在viewdidload中:

    self.angle = 0;
    self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(update) userInfo:nil repeats:YES];

angle 是 CGFloat 用于存储当前值以在更新方法中通过余弦函数计算 alpha:

-(void)update {
    self.angle += M_PI/36.0;
    if (self.angle > M_PI) self.angle = 0.0;
    CGFloat val = (1 + cos(self.angle)) / 2.0;
    dispatch_async(dispatch_get_main_queue(), ^{
        self.myLabel.alpha = val;
    });
}

您可以调整值 36.0 以使淡入/淡出更慢或更快。随着angle 的增加,val 将在 0 和 1 之间来回给出摆动值。然后使用 GCD 我们根据需要实时设置标签 alpha。当按下按钮移动到另一个视图控制器时(根据您的要求),您只需通过使其无效来停止计时器,标签将保持在设置的任何 alpha 值。

[self.myTimer invalidate];
self.myTimer = nil;
// CGFloat currentAlpha = self.myLabel.alpha;

从这里,您可以使用标签 alpha 做其他事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 2013-02-13
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    相关资源
    最近更新 更多