0

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.

Bhavesh Nayi
  • 705
  • 4
  • 15
Mickael Belhassen
  • 2,970
  • 1
  • 25
  • 46
  • you're setting the text color in the same animation, rather than blinking it, i.e the code you've got is the desired result e.g animate to this text color. You would need multiple animations to achieve this. Regardless of that I don't actually think textColor is animatable https://stackoverflow.com/questions/2426614/how-to-animate-the-textcolor-property-of-an-uilabel but you should use a transition – TommyBs May 08 '19 at 10:18
  • 1
    Possible duplicate of [How to animate the textColor property of an UILabel?](https://stackoverflow.com/questions/2426614/how-to-animate-the-textcolor-property-of-an-uilabel) – TommyBs May 08 '19 at 10:19
  • @TommyBs Thank you, but the real problem is to repeat the infinite animation: .repeat, .autoreverse – Mickael Belhassen May 08 '19 at 10:23

2 Answers2

2

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.

enter image description here

TheTiger
  • 13,264
  • 3
  • 57
  • 82
0
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()

enter image description here

RajeshKumar R
  • 15,445
  • 2
  • 38
  • 70