Swift 3, iOS 10, macOS 10.12.4
I am building an app that runs on both iOS and Mac. On the iOS side, I have successfully animated a UIView
. When the user taps on something, a popup appears and animates into position. Here's my code inside the tap event:
self.popupConstraintX.constant = x
self.popupConstraintY.constant = y
UIView.animate(withDuration: 0.25 , delay: 0.0, options: .curveLinear, animations: {
self.graphPopup.alpha = 1.0
self.layoutIfNeeded()
}, completion:nil)
In this case, self
refers to a UITableViewCell
that holds the graphPopup
.
I have built the same thing on the Mac side, but I'm trying to animate graphPopup
which is now an NSView
. Here's what I have so far inside my click event:
self.popupConstraintX.constant = x
self.popupConstraintY.constant = y
self.view.layoutSubtreeIfNeeded()
NSAnimationContext.runAnimationGroup({_ in
self.graphPopup.alphaValue = 1.0
//Indicate the duration of the animation
NSAnimationContext.current().duration = 0.25
NSAnimationContext.current().allowsImplicitAnimation = true
self.view.updateConstraints()
self.view.layoutSubtreeIfNeeded()
}, completionHandler:nil)
Here self
refers to the containing NSViewController
. Nothing animates--not the position or the alpha
of graphPopup
. It just appears and disappears like it's on an Atari in 1985.
Any idea what I'm doing wrong with my NSView
animation?
Update
For posterity's sake, here is the working code as suggested by BJ (with a slight tweak to use the implicit animation context):
self.popupConstraintX.constant = x
self.popupConstraintY.constant = y
NSAnimationContext.runAnimationGroup({context in
context.duration = 0.25
context.allowsImplicitAnimation = true
self.graphPopup.alphaValue = 1.0
self.view.layoutSubtreeIfNeeded()
}, completionHandler:nil)
The modification of alphaValue
is happening before you have turned on implicit animation, so the alpha will not be animated. It's unclear to me whether that was intentional or not.
The view is not animating to the position given by the popupConstraint
s, because you're not actually doing anything inside the animation block that would cause the view's frame to change. In order to trigger an implicit animation, you must not only update constraints; you must also ensure that the view's frame
changes within the animation block. If you're using AutoLayout, this is usually done by calling layoutSubtreeIfNeeded
.
However, because you updated the constraints and called layoutSubtreeIfNeeded()
prior to the animation block, there are no additional frame changes left to make inside the block (unless there's something happening down in updateConstraints()
which you haven't shown us.)
You should remove the first call to layoutSubtreeIfNeeded()
, or if it's still necessary, put it above the popupConstraint
modifications. Then, when you call layoutSubtreeIfNeeded()
within the animation block, a new frame will be set based on those changed constraints, and you should see animation happening.
Swift 5
animator()
is the key.
You can simply do like this:
NSAnimationContext.runAnimationGroup({ context in
//Indicate the duration of the animation
context.duration = 0.25
self.popupConstraintX.animator().constant = x
self.popupConstraintY.animator().constant = y
self.graphPopup.animator().alphaValue = 1.0
}, completionHandler:nil)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With