Delay in DispatchQueue.main.async - swift

I have a design like below flow. I need to set delay between 5th and 6th steps for 0.3second. I tried below options but couldn't get any result.
My question is, how can I achieve this?
Note: 13seconds for see the animation.
Flow
Task Handler // for webService request
Closure Handler // for trigger ViewController
DispatchQueue.main.async // for Update UI
First Animation
Second Animation
Navigation to next screen
Test 1
Timer.scheduledTimer(withTimeInterval: 13, repeats: false, block: {})
Test 2
UIView.animate(withDuration: 13, animations: {
// nothing should be happened
self.ivSuccessMark.alpha = 0.99 // for dummy animation diff
}, completion: { (completion) in
// navigation
})
Test 3
perform(_:with:afterDelay:)

Try this one
UIView.animate(withDuration: 0.5, delay: 0.3, options: [.repeat, .curveEaseOut, .autoreverse], animations: {
// animation stuff
}, completion: { _ in
// do stuff once animation is complete
})

Try this one I hope it help you(Up to 4 seconds Stop all Action in view)
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
// Put your code which should be executed with a delay here
})

Related

UIView.animate() issue

I have a code, where UI elements are changed after user interaction. I use UIView.animate() to refresh UI. The code is pretty simple:
UIView.animate(withDuration: 1.0) {
self.fadeIn()
} completion: { _ in
UIView.animate(withDuration: 1.0) {
self.fadeOut()
}
}
Very important point is that total animation duration from beginning to the end should be 2 seconds. But sometimes, there are no UI changes in fadeIn(), and UIView.animate() just get immediately to completion block. But in that option I want to have a delay for duration time (1 sec), and only after that get to completion block to fadeOut. How I can force animate with duration even if it's nothing to animate in animation block? Thanks in advance!
Maybe don't call fadeOut() in the completion block, and just make sure that it's called with one second delay after the fadeIn() is called?
UIView.animate(withDuration: 1.0) {
self.fadeIn()
}
UIView.animate(withDuration: 1.0, delay: 1.0) {
self.fadeOut()
}

Why is my button being removed from its superview before it completes its animation?

I am trying to move an my button to a certain part of the screen [as a custom button class GameBlock] and then remove it from its superview. However, it is acting weird in the sense that it removes itself from the superview before it completes the animation and I have no clue why. May somebody please help me out? I appreciate it.
UIView.animate(withDuration: movementTime,
delay: 0.0,
options: [],
animations: {
movedBlock.center = gridCoord[hitBlock.x][hitBlock.y]
},
completion: nil)
if movedBlock.center == gridCoord[hitBlock.x][hitBlock.y] {
movedBlock.removeFromSuperview()
}
If I understand your problem, this should works. Your view will be removed after the animation. The completion closure will be called at the end of the animation.
UIView.animate(withDuration: movementTime,
delay: 0.0,
options: [],
animations: {
movedBlock.center = gridCoord[hitBlock.x][hitBlock.y]
},
completion: { _ in
if movedBlock.center == gridCoord[hitBlock.x][hitBlock.y] {
movedBlock.removeFromSuperview()
}
})

Overlapping UIView animation canceling the first completion block

I have two buttons to move views. When I press the first button it will move a view and the other will move it back.
The first animation has a completion block, but I want to prevent this block from executing when the user moves the view back before the completion is done.
I have tried using solutions given to other questions similar to this but it doesn't seem to stop the execution of the first completion block.
#IBOutlet func moveView(sender: AnyObject) {
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .AllowUserInteraction, animations: { /* animation */ }) { _ in /* completion */ }
}
#IBOutlet func moveBack(sender: AnyObject) {
UIView.animateWithDuration(0.0, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .BeginFromCurrentState, animations: { /* animation */ }) { _ in /* completion */ }
}
I also tried removing all the animations and the completion parameter will be false but the animation will just jump to the end and animate from there.
Any ideas is very much appreciated.
You may use boolean flag to achieve the desired functionality like as under:
var moveViewFlag = false
var moveBackFlag = false
#IBOutlet func moveView(sender: AnyObject) {
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .AllowUserInteraction, animations: { /* animation */ }) { _ in /* completion */
//inside completion block make the moveBackFlag to true
moveBackFlag = true
}
}
#IBOutlet func moveBack(sender: AnyObject) {
UIView.animateWithDuration(0.0, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .BeginFromCurrentState, animations: { /* animation */ }) { _ in /* completion */
//inside completion block make the moveBackFlag to true
moveViewFlag = true
if moveBackFlag{
//do whatever you want to do!
}
}
}
Hope this helps.
Than you should create a custom class and handle that inside the class to avoid cluttered flags.
After searching for a while I think I've found a solution. To get the completion block to return false, the animation has to be removed. But by doing so, the animation will jump to the "end state" so to prevent this I used:
object.layer.frame = object.layer.presentationLayer()!.frame
object.layer.removeAllAnimations()
From here I can start my new animation (moving back the object) without worrying about the completion block of the first animation. Information
I'm not sure if this is how it should be done or if there's a better way of doing this.

UIView animations in Swift

I am trying to execute following code.
UIView.animateWithDuration(5.0, animations: {
println("animations")
}, completion: { finished in
println("completion")
})
So Here completion block is called immediately before 5 sec animation duration. Don't know what is wrong here.
Please let me know for proper code.
You should add some view for animation:
UIView.animateWithDuration(5.0, animations: {
someView.alpha = 0
println("animations")
}, completion: { finished in
println("completion")
})
You don't have any animation sequence in your animations block, try animating your current view and check it'll work fine.
UIView.animateWithDuration(5.0, animations: {
self.view.alpha = 0.5;
print("animations")
}, completion: { finished in
self.view.alpha = 1.0;
print("completion")
})

animateWithDuration Animates Once But Not Twice

I have this piece of animation in a switch statement that runs and does what it's supposed to. The animation is called successfully every twenty seconds inside a timer. However, the animation does not happen any time but the first time. In my code below you will see println statements that I used to try and highlight the problem. Each println statement prints but no animation happens. What is it that I'm missing?
func popAnimation(indexNumber: Int) {
let image = self.overlayImageView[indexNumber]
image.hidden = false
image.alpha = 0.0
UIView.animateWithDuration(0.75, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1.0, options: nil, animations: { () -> Void in
println("animation ran")
println(image.alpha)
image.image = UIImage(named: "lowCountOverlay")
image.alpha = 1.0
}, completion: { (Bool) -> Void in
UIView.animateWithDuration(0.75, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1.0, options: nil, animations: { () -> Void in
println("animation 2 ran")
println(image.alpha)
image.alpha = 0.0
}, completion: { (Bool) -> Void in
println("animation 3 ran")
image.hidden = true
})
})
}
UPDATE: If I remove image.hidden from the second completion block it works fine and animates repeatedly. Which is interesting because if it's not hidden it should be covering other interactive content in the view, but it's not. The other content is perfectly accessible in simulator. The UIImageView image is definitely the top layer in Storyboard.
I could be off, but it seems like you're running from an NSTimer which may or may not be in the main thread.
UI updates need to take place in the main thread, try wrapping the completion handler in a GCD dispatch directed to the main thread like the following and see if that helps? Maybe even force the whole thing to the main thread.
UIView.animateWithDuration(0.75, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1.0, options: nil, animations: { () -> Void in
// First animation
}, , completion: { (Bool) -> Void in
dispatch_async(dispatch_get_main_queue(),{
// second animation
})
})
I think you need to look for your bug elsewhere. You don't seem to be missing anything in the codeā€”as I'm able to run the animation repeatedly without any issues. I've copied your code as-is to a separate project and the animation works every time.
Try replacing:
let image = self.overlayImageView[indexNumber]
image.hidden = false
image.alpha = 0.0
with
let image = self.overlayImageView[indexNumber]
image.superview.bringSubviewToFront(image)
image.hidden = false
image.alpha = 0.0