I'm noticing at various times throughout my app that when I call UIView.animateWithDuration
, if I have any other kind of auto-layout requests, or even something as simple as changing the constant of an NSLayoutConstraint
, those changes will also be animated even when they are NOT inside the animation block. For example: I have a UIViewController
that right after viewDidAppear
is called, will add an image which was chosen by the user to a UIScrollView
so that it can be resized and edited. I'm working on adding a little demonstration view with some GIF's to help the user when they first use the app. Once the view shows, it should add the image (I've set it to fit to their screen at first) to the scrollView, and then animate the demonstrationView
alpha from zero to 1.0. The problem I'm experiencing, is even though my function to add and resize the image assignImageChosen
is called before animateWithDuration
, and is outside the animation block, the changes in size constraints are also animated.
override func viewDidAppear(animated: Bool) {
if let image = startImage {
self.assignImageChosen(image)
currentlyEditing = true
}
if preLoadGame {
UIView.animateWithDuration(1.0, delay: 0.5, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.demonstrationView.alpha = 1.0
self.view.layoutIfNeeded()
}, completion: nil)
}
}
Here is the function assignImageChosen
:
func assignImageChosen(image: UIImage) {
var ratio:CGFloat!
let screen:CGFloat = max(self.scrollView.frame.height, self.scrollView.frame.width)
var maxImage:CGFloat!
if UIDevice.currentDevice().orientation.isPortrait {
if image.size.height >= image.size.width {
maxImage = max(image.size.height, image.size.width)
}
else {
maxImage = min(image.size.height, image.size.width)
}
}
else {
if image.size.width >= image.size.height {
maxImage = max(image.size.height, image.size.width)
}
else {
maxImage = min(image.size.height, image.size.width)
}
}
if maxImage > screen {
ratio = screen/maxImage
}
else {
ratio = 1.0
}
self.imageView.image = image
self.imageHeight.constant = image.size.height * ratio
self.scrollView.contentSize.height = image.size.height * ratio
self.imageWidth.constant = image.size.width * ratio
self.scrollView.contentSize.width = image.size.width * ratio
}
The variables imageHeight
and imageWidth
are both NSLayoutConstraint
's, and imageView
is the UIImageView
to which they are set. So once I change the image, I change the constraints so that the imageView inside the UIScrollView
is fit to the screen. The problem is that when I do it like this, even though the changes are called outside the animation block, those changes are still animated.
Here's a GIF example of what I'm trying (poorly) to communicate through words:
I have found a way to circumvent this issue, but it feels like a complete hack. I manually code the system to delay the execution of the animation by using the dispatch_after
command like so:
override func viewDidAppear(animated: Bool) {
if let image = startImage {
self.assignImageChosen(image)
currentlyEditing = true
}
if preLoadGame {
let delay = 0.5 * Double(NSEC_PER_SEC)
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(popTime, dispatch_get_main_queue(), {
UIView.animateWithDuration(1.0, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.demonstrationView.alpha = 1.0
self.view.layoutIfNeeded()
}, completion: nil)
})
}
}
So instead of using the delay
variable inside the animateWithDuration
function, I instead delay the execution of the function. It works, but I would think there must be a better way to do this! Why are those layout changes being animated when they aren't inside the animation block? How can I get around this in a proper, efficient manner?
Here is how it looks with my hack, and how I would imagine it should look without it:
I appreciate any help with this frustrating issue!