Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate Auto Layout Constraints and Alpha on NSView

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)
like image 606
Clifton Labrum Avatar asked May 10 '17 21:05

Clifton Labrum


2 Answers

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 popupConstraints, 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.

like image 86
BJ Homer Avatar answered Nov 30 '22 23:11

BJ Homer


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)
like image 34
M Afham Avatar answered Dec 01 '22 00:12

M Afham