Animation each UIView inside the StackView - ios

I need to animate a UIViews inside stackView like this.
This image is a gif 👆🏻 (click to show)
I create an UIView Extension like this
func fadeIn(duration: TimeInterval = 1.5, delay: TimeInterval = 0.0, completion: #escaping ((Bool) -> Void) = {(_: Bool) -> Void in }) {
self.alpha = 0.0
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.isHidden = false
self.alpha = 1.0
}, completion: completion)
}
And for each UIView inside the StackView assigned the animation like this
stackView.subviews.forEach { currentView in
currentView.fadeIn()
}
but all views appear at the same time. I try to add a delay time but doesn't work correctly. Any idea how to fix?

You can try
stackView.arrangedSubviews.enumerated().forEach { (index,item) in
item.fadeIn(delay:Double(index)*1.5)
}
with
func fadeIn(duration: TimeInterval = 1.5, delay: TimeInterval = 0.0, completion: #escaping ((Bool) -> Void) = {(_: Bool) -> Void in }) {
self.alpha = 0.0
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.isHidden = false
self.alpha = 1.0
}, completion: completion)
}

Related

How can I Use Alpha Extension For All Object in swift?

I have below code for changing the value of object like text,image , ... with Effect. and it work:
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.lblCityTemp.alpha = 0.0
self.imgCityIcon.alpha = 0.0
}, completion: {
(finished: Bool) -> Void in
//Once the label is completely invisible, set the text and fade it back in
self.imgCityIcon.image = UIImage(named: icon)
self.lblCityTemp.text = "\(temp)°"
// Fade in
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.lblCityTemp.alpha = 1.0
self.imgCityIcon.alpha = 1.0
}, completion: nil)
})
Now I want make a extension of this code that I use for all my object that I write below code:
extension NSObject {
func Fade (alphaOUT: Double,alphaIN: Double, input: Any) {
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.alpha = CGFloat(alphaOUT)
}, completion: {
(finished: Bool) -> Void in
// Fade in
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.alpha = CGFloat(alphaIN)
}, completion: nil)
})
}
}
But I have error on self word and I do not know how can I set value for every object like label, imageView , ....
How can I do this?
Is the extension is best way or no?
If no, so what is the best way?
The whole idea should be take some UIView and animate it. Then you need extension of UIView since this class has properties that you need to.
extension UIView { ... }
Anyway, what now if you need to do something when animation ends? Then you'll need completion handler parameter for your method
func fade(..., completion: #escaping () -> Void = { }) {
... which will be called after the first animation ends.
Next suggestions:
You can say that alpha parameters should be of type CGFloat, then you don’t have to convert Double to CGFloat
Also, what is input? I think you won't need it with this solution
Method name should start with small capital letter and for naming parameters you should use camelCase
extension UIView {
func fade(alphaOut: CGFloat, alphaIn: CGFloat, completion: #escaping () -> Void = { }) {
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut, animations: {
self.alpha = alphaOut
}, completion: { _ in
completion() // this is called when animation ends
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseIn, animations: {
self.alpha = alphaIn
})
})
}
}
Then when you need to call it, change what you need after animation ends in completion closure
imgCityIcon.fade(alphaOut: ___, alphaIn: ___) {
self.imgCityIcon.image = UIImage(named: icon)
}
Note that you're using old syntax for some stuff:
For example UIViewAnimationOptions.curveEaseIn has been renamed to UIView.AnimationOptions.curveEaseIn. I would suggest you to start using newer versions of Swift
You need to implement an extension for UIView instead of NSObject.
since NSObject doesn't have any property like alpha you will get an
error.
Coding Example:
extension UIView {
func Fade (alphaOUT: Double,alphaIN: Double, input: Any) {
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIView.AnimationOptions.curveEaseOut, animations: {
self.alpha = CGFloat(alphaOUT)
}, completion: {
(finished: Bool) -> Void in
// Fade in
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.alpha = CGFloat(alphaIN)
}, completion: nil)
})
}
}
class AnimationHelper {
class func Fade (alphaOUT: Double,alphaIN: Double, input: Any , yourLabel: UILabel, yourTextField: UITextField) {
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIView.AnimationOptions.curveEaseOut, animations: {
yourLabel.alpha = CGFloat(alphaOUT)
yourTextField.alpha = CGFloat(alphaOUT)
}, completion: {
(finished: Bool) -> Void in
// Fade in
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
// Access your text field and label here.
}, completion: nil)
})
}
}

animating UIButton on the flow

I have a UIButton in my application with an image.
I want to be able to call a function that flashes that button a number of times ( say 5 times)
I also want to be able to stop this flashing while it is running
Below is the important part of the code:
var flashesRemaining: Int = 5;
var isFlashing: Bool = false
#IBOutlet weak var btnMM: UIButton!
// Flash the button
#IBAction func flashMemoryButton(sender: AnyObject) {
print(self.flashesRemaining)
if self.flashesRemaining == 0 {
return
}
if !isFlashing {
self.btnMM.alpha = 1.0
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.curveEaseInOut, .repeat, .autoreverse, .allowUserInteraction], animations: {() -> Void in
self.btnMM.alpha = 0.0100000003
}, completion: {(finished: Bool) -> Void in })
isFlashing = true
}
else {
UIView.animate(withDuration: 0.1, delay: 0.0, options: [.curveEaseInOut, .beginFromCurrentState], animations: {() -> Void in
self.btnMM.alpha = 1.0
}, completion: {(finished: Bool) -> Void in })
}
self.flashesRemaining = self.flashesRemaining - 1
}
So I want to be able to call the above function like this, to start the flashing:
self.flashesRemaining = 5
self.flashMemoryButton(sender: self.btnMM)
and then if I want to disable the blinking I should just call:
self.flashesRemaining = 0
However the above code is not working at all. Once I call
self.flashMemoryButton(sender: self.btnMM)
I get the printout 5 and then the button keeps blinking for ever.
What am I missing here?
By the way the magical number 0.0100...3 is the minimum allowed alpha for a UIButton while maintaining user interactivity.
Here's the working code:
func flashMemoryButton() {
print(self.flashesRemaining)
if self.flashesRemaining == 0 {
btnMM.alpha = 1
return
}
if !isFlashing {
self.btnMM.alpha = 1.0
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.curveEaseInOut, .allowUserInteraction], animations: {() -> Void in
self.btnMM.alpha = 0.0100000003
}, completion: {(finished: Bool) -> Void in
if finished {
self.flashMemoryButton()
self.flashesRemaining = self.flashesRemaining - 1
}
})
isFlashing = true
}
else {
UIView.animate(withDuration: 0.1, delay: 0.0, options: [.curveEaseInOut, .beginFromCurrentState], animations: {() -> Void in
self.btnMM.alpha = 1.0
}, completion: {(finished: Bool) -> Void in
if finished {
self.flashMemoryButton()
}
})
isFlashing = false
}
}
Here's the changes I've made:
First, I removed .repeat and .autoreverse. This is because instead of the animation repeating itself, we want the flashMemoryButton method to be called multiple times.
Next, I added isFlashing = false in the else branch. This is so that when isFlashing is true, the button fades in the next time the method is called, and when isFlashing is false, the button fades out. You can think of isFlashing like a toggle.
When the fade in/out animations finish, I called flashMemoryButton() because when the animation finishes, you want to do another animation, right?
In the completion handler of the fade out animation, I decremented flashesRemaining. This is where you want to decrement it, not outside the if statement. If you put it outside, it will flash half the times you told it to.
You could use UIView.setAnimationRepeatCount; therefore you dont need flashesRemaining any more. You should also re-set the isFlashing-flag in the completion handler. Here my modified code:
var isFlashing: Bool = false
#IBOutlet weak var btnMM: UIButton!
#IBAction func flashMemoryButton(sender: AnyObject) {
if !isFlashing {
self.btnMM.alpha = 1.0
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.curveEaseInOut, .repeat, .autoreverse, .allowUserInteraction], animations: {() -> Void in
UIView.setAnimationRepeatCount(5)
self.btnMM.alpha = 0.0100000003
}, completion: {(finished: Bool) -> Void in
UIView.animate(withDuration: 0.1, delay: 0.0, options: [.curveEaseInOut, .beginFromCurrentState], animations: {() -> Void in
self.btnMM.alpha = 1.0
}, completion: {(finished: Bool) -> Void in self.isFlashing = false})
})
isFlashing = true
}
else {
UIView.animate(withDuration: 0.1, delay: 0.0, options: [.curveEaseInOut, .beginFromCurrentState], animations: {() -> Void in
self.btnMM.alpha = 1.0
}, completion: {(finished: Bool) -> Void in self.isFlashing = false})
}
}

FadeIn animation not work swift 2

Below is my code.
The fade out effect works fine. The fade in effect however is not animated .
I can not solve this problem. Thanks to all those that will help me.
Alpha is set 0 in storyboard
extension UIView {
func fadeIn(duration: NSTimeInterval = 3.0, delay: NSTimeInterval = 0.0, completion: ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveLinear, animations: {
self.alpha = 1.0
}, completion: completion) }
func fadeOut(duration: NSTimeInterval = 2.0, delay: NSTimeInterval = 3.0, completion: (Bool) -> Void = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.alpha = 0.0
}, completion: completion)
}
}
Calling UIView.animationWithDuration directly after it was called will cancel the previous animation even if you supply a delay in the function call. However, you can either use the completion function like #Daniel Hall suggested:
myView.fadeIn() { _ in
myView.fadeOut()
}
Or if you do the fadeOut in a different method that is being triggered by some event exactly after fadeIn you can use dispatch_after to execute after delay time ( which should be the fadeIn duration in your case)
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
self.myView.fadeOut()
}
Your code works fine for me inside a playground:
import UIKit
import XCPlayground
extension UIView {
func fadeIn(duration: NSTimeInterval = 3.0, delay: NSTimeInterval = 0.0, completion: ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveLinear, animations: {
self.alpha = 1.0
}, completion: completion)
}
func fadeOut(duration: NSTimeInterval = 2.0, delay: NSTimeInterval = 3.0, completion: (Bool) -> Void = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.alpha = 0.0
}, completion: completion)
}
}
let liveView = UIView(frame: CGRect(origin: CGPointZero, size: CGSize(width: 400, height: 400)))
XCPlaygroundPage.currentPage.liveView = liveView
let newView = UIView(frame: CGRect(x: 200, y: 200, width: 50, height: 50))
newView.backgroundColor = UIColor.greenColor()
newView.alpha = 0
liveView.addSubview(newView)
newView.fadeIn { _ in newView.fadeOut{ _ in newView.fadeIn() } }
It fades in, fades out on completion of the fade-in, then fades back in on completion of the fade-out.
Perhaps the issue it where / when you are calling the fadeIn() method on your view, and not a problem with your extension itself.

How to make a label fade in or out in swift

I am looking to make a label fade in, in viewDidLoad(), and then after a timer is at 3 fade out. I am not familiar with the fadein or fadeout functions.
How would I go about doing this?
My suggestion is to leverage Swift extensions to make the code a bit more modular and easy to use. For example, if you want to make multiple labels fadein/out or one label to fade in/out on multiple views, you would have to pass the animateWithDuration methods everywhere, which can be a hassle. A cleaner alternative is to create a file called UIView.swift (our UIView extension). Add the following code to this file:
import Foundation
extension UIView {
func fadeIn(duration: NSTimeInterval = 1.0, delay: NSTimeInterval = 0.0, completion: ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 1.0
}, completion: completion) }
func fadeOut(duration: NSTimeInterval = 1.0, delay: NSTimeInterval = 3.0, completion: (Bool) -> Void = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 0.0
}, completion: completion)
}
}
Now you can add fadeIn/fadeout functionality to any child of UIView (e.g., UILabel, UIImage, etc). Inside of your viewDidLoad() function, you can add :
self.statusLabel.alpha = 0
self.statusLabel.text = "Sample Text Here"
self.myLabel.fadeIn(completion: {
(finished: Bool) -> Void in
self.myLabel.fadeOut()
})
Now, you can use this sample code for Image views, labels, text views, scroll views, or any child of UIView as well. I hope this helps.
Even though the view has loaded, it may not be visible to the user when viewDidLoad is called. This means you might find your animations appears to have already started when you witness it. To overcome this issue, you'll want to start your animation in viewDidAppear instead.
As for the fadeIn and fadeOut functions - they don't exist. You'll need to write them yourself. Thankfully, it's very easy to do this. Something like the below might be good enough.
func fadeViewInThenOut(view : UIView, delay: NSTimeInterval) {
let animationDuration = 0.25
// Fade in the view
UIView.animateWithDuration(animationDuration, animations: { () -> Void in
view.alpha = 1
}) { (Bool) -> Void in
// After the animation completes, fade out the view after a delay
UIView.animateWithDuration(animationDuration, delay: delay, options: .CurveEaseInOut, animations: { () -> Void in
view.alpha = 0
},
completion: nil)
}
}
Answer updated for Swift 3 - Using extension
extension UIView {
func fadeIn(duration: TimeInterval = 1.0, delay: TimeInterval = 0.0, completion: #escaping ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.alpha = 1.0
}, completion: completion)
}
func fadeOut(duration: TimeInterval = 1.0, delay: TimeInterval = 3.0, completion: #escaping (Bool) -> Void = {(finished: Bool) -> Void in}) {
UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.alpha = 0.0
}, completion: completion)
}
}
Usage:
self.statusLabel.alpha = 0
self.statusLabel.text = "Sample Text Here"
self.myLabel.fadeIn(completion: {
(finished: Bool) -> Void in
self.myLabel.fadeOut()
})
Update Swift 3.1 - on #Andy code
func fadeViewInThenOut(view : UIView, delay: TimeInterval) {
let animationDuration = 0.25
// Fade in the view
UIView.animate(withDuration: animationDuration, animations: { () -> Void in
view.alpha = 1
}) { (Bool) -> Void in
// After the animation completes, fade out the view after a delay
UIView.animate(withDuration: animationDuration, delay: delay, options: [.curveEaseOut], animations: { () -> Void in
view.alpha = 0
}, completion: nil)
}
}
Swift 5
This worked well for me. I placed the label inside the "cardHeaderView".
#IBOutlet weak var cardHeaderView: UIView!
Place this inside the "viewDidAppear". I went with a delay of zero so the animation would start right away.
fadeViewInThenOut(view: cardHeaderView, delay: 0)
Here is the function.
func fadeViewInThenOut(view : UIView, delay: TimeInterval) {
let animationDuration = 1.5
UIView.animate(withDuration: animationDuration, delay: delay, options: [UIView.AnimationOptions.autoreverse, UIView.AnimationOptions.repeat], animations: {
view.alpha = 0
}, completion: nil)
}
SWIFT 4.2
extension UIView {
func fadeIn(duration: TimeInterval = 1.0, delay: TimeInterval = 0.0, completion: #escaping ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
UIView.animate(withDuration: duration, delay: delay, options: .curveEaseIn, animations: {
self.alpha = 1.0
}, completion: completion)
}
func fadeOut(duration: TimeInterval = 1.0, delay: TimeInterval = 3.0, completion: #escaping (Bool) -> Void = {(finished: Bool) -> Void in}) {
UIView.animate(withDuration: duration, delay: delay, options: .curveEaseIn, animations: {
self.alpha = 0.0
}, completion: completion)
}
}

How to make a button flash or blink?

I am trying to change a button's color (just a flash/blink) to green when a scan is correct and red when there's a problem. I am able to do this with a view like so
func flashBG(){
UIView.animateWithDuration(0.7, animations: {
self.view.backgroundColor = UIColor.greenColor()
})
}
But with a button it stays green
func flashBtn(){
UIButton.animateWithDuration(0.5, animations: {
self.buttonScan.backgroundColor = UIColor.greenColor()
})
}
I have created the button by code
func setupScanButton() {
let X_Co = (self.view.frame.size.width - 100)/2
let Y_Co = (self.viewForLayer.frame.size.height + 36/2)
buttonScan.frame = CGRectMake(X_Co,Y_Co,100,100)
buttonScan.layer.borderColor = UIColor.whiteColor().CGColor
buttonScan.layer.borderWidth = 2
buttonScan.layer.cornerRadius = 50
buttonScan.setTitle("Scan", forState: .Normal)
buttonScan.backgroundColor = UIColor.blueColor()
buttonScan.addTarget(self, action: "buttonScanAction", forControlEvents: .TouchUpInside)
buttonScan.setTitleColor(UIColor(red:255/255, green: 255/255, blue:255/255, alpha: 1), forState: UIControlState.Normal)
self.view.addSubview(buttonScan)
}
Should i call setupScanButton() again?
This should work in Swift 4
extension UIView{
func blink() {
self.alpha = 0.2
UIView.animate(withDuration: 1, delay: 0.0, options: [.curveLinear, .repeat, .autoreverse], animations: {self.alpha = 1.0}, completion: nil)
}
}
This will start and stop a flashing button onClick, if you only want to flash the button immediately just use the first statement.
var flashing = false
#IBAction func btnFlash_Clicked(sender: AnyObject) {
if !flashing{
self.buttonScan.alpha = 1.0
UIView.animateWithDuration(0.5, delay: 0.0, options: [.CurveEaseInOut, .Repeat, .Autoreverse, .AllowUserInteraction], animations: {() -> Void in
self.buttonScan.alpha = 0.0
}, completion: {(finished: Bool) -> Void in
})
flashing = true
}
else{
UIView.animateWithDuration(0.1, delay: 0.0, options: [.CurveEaseInOut, .BeginFromCurrentState], animations: {() -> Void in
self.buttonScan.alpha = 1.0
}, completion: {(finished: Bool) -> Void in
})
}
}
Swift 5.x version
An updated version with extension.
extension UIView {
func blink(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, alpha: CGFloat = 0.0) {
UIView.animate(withDuration: duration, delay: delay, options: [.curveEaseInOut, .repeat, .autoreverse], animations: {
self.alpha = alpha
})
}
}
To call the function:
button.blink() // without parameters
button.blink(duration: 1, delay: 0.1, alpha: 0.2) // with parameters
I hope that will solve your problem.
buttonScan.alpha = 1.0
UIView.animate(withDuration: 1.0, delay: 1.0, options: UIView.AnimationOptions.curveEaseOut, animations: {
buttonScan.alpha = 0.0
}, completion: nil)
Swift 4:
I've maked an extension with some useful options:
extension UIButton {
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return self.bounds.contains(point) ? self : nil
}
func blink(enabled: Bool = true, duration: CFTimeInterval = 1.0, stopAfter: CFTimeInterval = 0.0 ) {
enabled ? (UIView.animate(withDuration: duration, //Time duration you want,
delay: 0.0,
options: [.curveEaseInOut, .autoreverse, .repeat],
animations: { [weak self] in self?.alpha = 0.0 },
completion: { [weak self] _ in self?.alpha = 1.0 })) : self.layer.removeAllAnimations()
if !stopAfter.isEqual(to: 0.0) && enabled {
DispatchQueue.main.asyncAfter(deadline: .now() + stopAfter) { [weak self] in
self?.layer.removeAllAnimations()
}
}
}
}
First of all, I've overrided the hittest function to enabling the touch also when the button have the alpha equals to 0.0 (transparent) during the animation.
Then , all input vars have a default value so you can launch the blink() method without parameters
I've introduced also the enabled parameter to start or stop the animations on your button.
Finally, if you want you can stop animation after a specific time with the stopAfter parameter.
Usage:
yourButton.blink() // infinite blink effect with the default duration of 1 second
yourButton.blink(enabled:false) // stop the animation
yourButton.blink(duration: 2.0) // slowly the animation to 2 seconds
yourButton.blink(stopAfter:5.0) // the animation stops after 5 seconds.
Typical uses:
yourButton.blink(duration: 1.5, stopAfter:10.0)
// your code..
yourButton.blink()
// other code..
yourButton.blink(enabled:false)
You can try something like this:
extension UIView {
func blink() {
UIView.animateWithDuration(0.5, //Time duration you want,
delay: 0.0,
options: [.CurveEaseInOut, .Autoreverse, .Repeat],
animations: { [weak self] in self?.alpha = 0.0 },
completion: { [weak self] _ in self?.alpha = 1.0 })
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,Int64(2 * NSEC_PER_SEC)),dispatch_get_main_queue()){
[weak self] in
self?.layer.removeAllAnimations()
}
}
}
//MARK : Usage
yourButton.flash()
extension UIButton {
func flash() {
let flash = CABasicAnimation(keyPath: "opacity")
flash.duration = 0.5
flash.fromValue = 1
flash.toValue = 0.1
flash.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
flash.autoreverses = true
flash.repeatCount = 3
layer.add(flash, forKey: nil)
}
}
Swift 3.0
func btnFlash_Clicked(sender: AnyObject) {
if !flashing{
callButton.alpha = 1.0
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.allowUserInteraction], animations: {() -> Void in
callButton.alpha = 0.5
}, completion: {(finished: Bool) -> Void in
})
flashing = true
}
else{
flashing = false
callButton.alpha = 0.5
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.allowUserInteraction], animations: {() -> Void in
callButton.alpha = 1.0
}, completion: {(finished: Bool) -> Void in
})
}
}
with UIViewPropertyAnimator and Swift 5
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1, delay: 0, options: [.curveLinear,.repeat], animations: {
UIView.setAnimationRepeatCount(3000)
self.buttonScan.alpha = 0.0
}, completion: {_ in })
Swift 3.0
func animateFlash() {
flashView.alpha = 0
flashView.isHidden = false
UIView.animate(withDuration: 0.3, animations: { flashView.alpha = 1.0 }) { finished in flashView.isHidden = true }
}
This UIView extension "blinks" a view and changes the background colour:
/**
Blinks a view with a given duration and optional color.
- Parameter duration: The duration of the blink.
- Parameter color: The color of the blink.
*/
public func blink(withDuration duration: Double = 0.25, color: UIColor? = nil) {
alpha = 0.2
UIView.animate(withDuration: duration, delay: 0.0, options: [.curveEaseInOut], animations: {
self.alpha = 1.0
})
guard let newBackgroundColor = color else { return }
let oldBackgroundColor = backgroundColor
UIView.animate(withDuration: duration, delay: 0.0, options: [.curveEaseInOut], animations: {
self.backgroundColor = newBackgroundColor
self.backgroundColor = oldBackgroundColor
})
}
You would then use as follows:
buttonScan.blink(color: .green)
myButton.alpha = 0.7
UIView.animate(withDuration: 0.3,
delay: 1.0,
options: [UIView.AnimationOptions.curveLinear, UIView.AnimationOptions.repeat, UIView.AnimationOptions.autoreverse],
animations: { myButton.alpha = 1.0 },
completion: nil)
Another smoothly animating version for Swift 5:
public extension UIView {
func blink(duration: TimeInterval) {
let initialAlpha: CGFloat = 1
let finalAlpha: CGFloat = 0.2
alpha = initialAlpha
UIView.animateKeyframes(withDuration: duration, delay: 0, options: .beginFromCurrentState) {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
self.alpha = finalAlpha
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
self.alpha = initialAlpha
}
}
}
}

Resources