I'm creating an autolayout-friendly split view class for one of my applications. Among its various features is that it can collapse panes, and can animate their collapse, much as you might have seen NSSplitView do.
Since I'm using constraints, I'm achieving this by placing a required width = (current width) constraint on the pane, and then setting the constraint's constant to 0 in an animated fashion:
- (NSLayoutConstraint*)newHiddenConstraintAnimated:(BOOL)animated {
NSLayoutConstraint * constraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:NSWidth(self.view.frame)];
constraint.priority = NSLayoutPriorityRequired;
CABasicAnimation * anim = [CABasicAnimation animation];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
anim.duration = 0.2;
constraint.animations = [NSDictionary dictionaryWithObject:anim forKey:@"constant"];
[self.view addConstraint:constraint];
[(animated ? constraint.animator : constraint) setConstant:0.0];
return constraint;
}
This works beautifully. Unfortunately, expanding the pane later does not fare so well.
- (void)removeHiddenConstraintAnimated:(BOOL)animated {
if(!animated) {
[self.view removeConstraint:self.hiddenConstraint];
}
else {
NSLayoutConstraint * constraint = self.hiddenConstraint;
NSView * theView = self.view;
[NSAnimationContext beginGrouping];
[constraint.animator setConstant:self.width];
[NSAnimationContext currentContext].completionHandler = ^{
[theView removeConstraint:constraint];
};
[NSAnimationContext endGrouping];
}
self.hiddenConstraint = nil;
}
If I insert some timing code, I can see that the completion handler fires almost instantly, removing the constraint before it has time to animate. Setting a duration on the NSAnimationContext has no effect.
Any idea what I could be doing wrong here?