简体   繁体   中英

Swift: UILabel, blink textColor animated

I want to flash my textColor of UILabel fromColor toColor, but I can not do it. Can you help me, here's what I've done :

extension UILabel {

    func blinkTextColor(fromColor: UIColor, toColor: UIColor, duration: TimeInterval, completion: ((_ view: UIView) -> ())? = nil) {
        UIView.animate(withDuration: duration, delay: 0.0, options: [.curveLinear, .repeat, .autoreverse, .allowUserInteraction], animations: {
            self.textColor = fromColor
            self.textColor = toColor
        }, completion: { _ in
            completion?(self)
        })
    }

}

It doesn't work.

You need to take two colours variables and swap them once animation finished and call the colour changing function recursively.

I answered once here Animate CAGradientLayer in Swift . It looks like same thing.

Although I tried and below is the code which worked for me.
For the convenience I created a custom class of UILabel which can be use easily.

class BlinkLabel: UILabel, CAAnimationDelegate {

    var colours: [UIColor] = []
    var speed: Double = 1.0
    fileprivate var shouldAnimate = true
    fileprivate var currentColourIndex = 0

    func startBlinking() {
        if colours.count <= 1 {
            /// Can not blink
            return
        }

        shouldAnimate = true
        currentColourIndex = 0
        let toColor = self.colours[self.currentColourIndex]
        animateToColor(toColor)
    }

    func stopBlinking() {
        shouldAnimate = false
        self.layer.removeAllAnimations()
    }

    fileprivate func animateToColor(_ color: UIColor) {

        if !shouldAnimate {return}

        let changeColor = CATransition()
        changeColor.duration = speed
        changeColor.type = .fade
        changeColor.repeatCount = 1
        changeColor.delegate = self
        changeColor.isRemovedOnCompletion = true
        CATransaction.begin()
        CATransaction.setCompletionBlock {
            self.layer.add(changeColor, forKey: nil)
            self.textColor = color
        }
        CATransaction.commit()
    }

    // MARK:- CAAnimationDelegate
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if flag {

            if !self.shouldAnimate {return}

            /// Calculating the next colour
            self.currentColourIndex += 1
            if self.currentColourIndex == self.colours.count {
                self.currentColourIndex = 0
            }

            let toColor = self.colours[self.currentColourIndex]

            /// You can remove this delay and directly call the function self.animateToColor(toColor) I just gave this to increase the visible time for each colour.
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: {
                self.animateToColor(toColor)
            })
        }
    }
}

Usage:

label.colours = [.red, .green, .blue, .orange]
label.speed = 1.0
label.startBlinking()

/// Stop after 10 seconds
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 10) {
    self.label.stopBlinking()
}

You can animate label with multiple colours.

在此处输入图片说明

let changeColor = CATransition()
changeColor.duration = 1
changeColor.type = .fade
changeColor.repeatCount = Float.infinity
CATransaction.begin()
CATransaction.setCompletionBlock {
    self.lbl.layer.add(changeColor, forKey: nil)
    self.lbl.textColor = .green
}
self.lbl.textColor = .red
CATransaction.commit()

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM