淡入和淡出UILabel,每次更改屏幕上的文本

时间:2018-12-03 19:49:54

标签: swift uilabel

我正在尝试达到以下效果

enter image description here

我目前具有如下创建的堆栈视图

class OnboardingWelcomeMessageStackView: UIStackView {

    private lazy var retriggerAnimation = true

    let messageHeader: UILabel = {
        let label = UILabel()
        label.text = OnboardingConstants.chatbotGreeting
        label.textColor = .white
        label.font = UIFont.boldSystemFont(ofSize: 24)
        label.alpha = 0
        label.numberOfLines = 0
        label.textAlignment = .center
        label.sizeToFit()
        return label
    }()

    let messageBody: UILabel = {
        let label = UILabel()
        label.text = OnboardingConstants.chatbotPurpose
        label.textColor = .white
        label.font = UIFont.systemFont(ofSize: 16, weight: .medium)
        label.alpha = 0
        label.numberOfLines = 0
        label.textAlignment = .center
        label.sizeToFit()
        return label
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupStackview()
        animateOnLoad()
    }

    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func animateOnLoad() -> Void {
        let duration: TimeInterval = 7

        UIView.animateKeyframes(withDuration: duration, delay: 0.3, options: .calculationModeLinear, animations: {
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1 / duration, animations: {
                self.messageHeader.alpha = 1
            })
            UIView.addKeyframe(withRelativeStartTime: 3 / duration, relativeDuration: 1 / duration, animations: {
                self.messageBody.alpha = 1
            })
            UIView.addKeyframe(withRelativeStartTime: 6 / duration, relativeDuration: 1 / duration, animations: {
                if self.retriggerAnimation {
                    self.messageHeader.alpha = 0
                    self.messageBody.alpha = 0
                }
            })
        }) { (_) in
            if self.retriggerAnimation {
                self.updateLabelText()
                self.animateOnLoad()
            }
        }
    }

    fileprivate func updateLabelText() -> Void {
        retriggerAnimation = false
        messageHeader.text = OnboardingConstants.chatbotIntroduction
        messageBody.text = OnboardingConstants.chatbotOnboardingWelcome
    }

    fileprivate func setupStackview() -> Void {
        self.addArrangedSubview(messageHeader)
        self.addArrangedSubview(messageBody)
    }
}

基本上,一旦添加了视图,我就会调用animateOnLoad,然后再次调用它并设置属性以防止其再次运行。

这感觉很hacky,老实说我不喜欢这样。我怎样才能达到这种效果?什么是最佳实践/最有效的方法?

1 个答案:

答案 0 :(得分:0)

关于此类问题,最佳实践始终是引入本地推理。

因此,您可以像这样创建自定义动画功能。

private func fade(labels : UILabel..., toAlpha alpha : CGFloat, duration : TimeInterval, completion : ((Bool)->Void)?){
    UIView.animate(withDuration: duration, animations: {
        labels.forEach({$0.alpha = alpha})
    }, completion: completion)
}

然后像这样

调用viewDidAppear中的函数
override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        fade(labels: label1, toAlpha: 1, duration: 1) { (_) in
            self.fade(labels: self.label2, toAlpha: 1, duration: 1, completion: { (_) in
                self.fade(labels: self.label1, self.label2, toAlpha: 0, duration: 1, completion: { (_) in
                    self.fade(labels: self.label1, toAlpha: 1, duration: 1, completion: { (_) in
                        self.fade(labels: self.label2, toAlpha: 1, duration: 1, completion: nil)
                    })
                })
            })
        }
    }

我所写的将执行与您所提供的完全相同的衰落序列。

您可以选择编写更好的帮助程序功能来分隔职责。.但是您应该了解一下

此外,请记住使用弱者或无人者解决保留周期问题。