First time animating is glitchy - ios

I am animating a view gradientView in/out using the following:
func hideOrShowGradientView(hide: Bool) {
UIView.animate(withDuration: 0.4, animations: {
self.gradientView.isHidden = hide
})
}
This works well, but on the first time, there is no animation. It just appears. On the second and third time it works wonderfully. I've tried calling the animate block on the main thread but no luck there. Why is this animation failing to occur on the first and only first time around? Should I be using another animation method?

Have you tried calling self.view.layoutIfNeeded(). It forces the view and it's subviews to complete any of it's pending animations immediately, which might be interfering with your animation. You can use it like this:
func hideOrShowGradientView(hide: Bool) {
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.4, animations: {
self.gradientView.isHidden = hide
self.view.layoutIfNeeded()
})
}
Apple recommends calling layoutIfNeeded() twice, once before the animation block which forces a redraw on the view and it's subviews, and it completes any pending animations on the view without waiting for the next update cycle, and call it the second time inside the animation block to make sure that the animation changes will be applied immediately.

I had too much going on the main thread in the init method, which was being called only on the first time the view was being presented. Moved unnecessary initialization into view did appear

Related

How to ensure UITableView header cell subview with repeating animation continues animating after a reloadData, user scroll, etc?

I have a ViewController with a header cell that is working well, except that one view in the header cell has a repeating animation that should continue animating endlessly when particular conditions are set in the view controller. I can start the animation sometimes successfully in viewDidLoad and restart it in my handler for the .appDidBecomeActive notification. However when the user scrolls or pulls to refresh the tableview data, the animation stops. I did override the scrollViewDidEndDragging & scrollViewDidEndDecelerating methods to restart it, but its not actually reliably restarting the animation. Clues?
UIView.animate(withDuration: 2.0,
delay: 0.0,
options: [.curveEaseInOut, .autoreverse, .repeat, .beginFromCurrentState],
animations: { self.headerCellAnimatedSubview?.alpha = 1.0 },
completion: { _ in self.headerCellAnimatedSubview?.alpha = 0.0 }
)
After some help I found that adding the animation call to the UITableViewHeaderCell class's override of didMoveToWindow the animation will restart after scroll. However as expected I also had to respond to the appDidBecomeActive notification to restart the animation when the app returns fro background.

How to set an animation once the view controller is loaded

My goal is to set off an animation when my second viewController is loaded. How do call the function once the view is loaded?
Here is the code:
UIView.animate(withDuration: 1.5, animations: {self.greyScreen.frame.origin.y = -0.39*self.screenHeight}, completion: nil)
Any advice much appreciated!
viewDidAppear() is the method of UIViewContoller Life Cycle which is called once the screen is completely visible i.e. loaded all views into the memory hierarchy. So put your this block of animation into this method. You'll get your animation effect
Place that code inside viewDidAppear.
viewDidAppear is called when the view is shown on the device, so adding that code to this method will trigger the animation as soon as the view is displayed.

When animating view with UIView.animate other views are also needlessly animated

I'm wondering why views in my custom TableViewCells are affected by animation which should animate only 2 views in my floating pager (which is even not in TableView's view hierarchy..
UIView.animate(withDuration: 0.3) {
self.stateIndicator.isHiddenInStackView = true
self.loaderIndicator.isHiddenInStackView = false
}
When I comment out animation block everything stops animating.
Attached GIF describes everything (Blue views gets animated corner radius, badges 'flies in' instead of just appearing):
UIView.animate strange behavior
Any help or hint will be appreciated :).
Regards Tom.
Write the things which you don't want to animate in the block
UIView.performWithoutAnimation {
//Write your code here
}
I make my animation in main queue and it worked.
For example
DispatchQueue.main.async {
//Write animation code here
}

Swift - removeAllAnimations() - One animation after the other

So I animated a button to move to a specific point (CGPoint) on the screen when the view loads. I also added a swipeGestureRecogniser to make it that if the user swipes left, than the animation will stop and a new one will start that takes the button to a different CGPoint. I did this by calling the removeAllAnimations() method on the button. The problem is that when the user swipes left, the button finishes the first animation without animating. So it doesn't stop and start the new animation, but rather it jumps to the end of the first animation and then continues to the next animation. Is there a way to stop the first animation and seamlessly start the next?
This is the code:
It's working as expected. At the time you call removeAllAnimations(), there's only one animation to be removed - the second one will be added in first's completion block. So instead of nesting animations, you can try something like that:
// first animation
UIView.animate(withDuration: 5, delay: 0, options: .curveLinear, animations: { /... }, completion: { //... })
// second animation
UIView.animate(withDuration: 5, delay: 5, animations: { /... })

Animate NSLayoutConstraint & view simultaneously in separate blocks

I have two relatively simple animations. One is animating the top constraint of a UIButton so that it slides up. The other is animating the background color on a UIView.
self.buttonAnimationConstant.constant = 0
self.view.layoutIfNeeded() // ensure the constraint is at 0
self.buttonAnimationConstraint.constant = 100
UIView.animateWithDuration(0.25, delay: 0.0) {
self.view.layoutIfNeeded()
}
and my color animation:
UIView.animateWithDuration(0.25, delay: 0.0) {
self.colorView.backgroundColor = UIColor.purpleColor()
}
If I try executing them at the same time, then the button will animate up but it cancels the color animation, presumably because of view.layoutIfNeeded. Note that these two animations are in separate places so they can't be joined into one block (one sits at the view controller level, the other embedded inside a custom view but both within the same view controller). How can I animate both a constraint and a view property such that one doesn't cancel the other?
Essentially the issue is how do you go about animating both a constraint and a view that sit in the same view hierarchy?
Animation blocks do not cancel each other. The issue here is this line:
self.view.layoutIfNeeded() // ensure the constraint is at 0
Calling layoutIfNeeded outside an animation block will cancel your animations (because they set a new value for the values you animate) and there is not much you can do to prevent that. What you could do is making sure that no layoutIfNeeded is called outside an animation block while performing an animation. Of course this does not happen if the views are not in the same view hierarchy.

Resources