NSLayoutConstraint.constant忽略动画

Bre*_*don 16 cocoa core-animation autolayout nsanimationcontext

我正在为我的一个应用程序创建一个自动布局友好的拆分视图类.它的各种功能之一是它可以折叠窗格,并且可以动画它们的崩溃,就像你可能已经看过NSSplitView那样.

由于我正在使用约束,我通过在窗格上放置一个必需的width =(当前宽度)约束,然后以动画方式将约束的常量设置为0来实现此目的:

- (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;
}
Run Code Online (Sandbox Code Playgroud)

这很好用.不幸的是,稍后扩展窗格并不是很好.

- (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;
}
Run Code Online (Sandbox Code Playgroud)

如果我插入一些计时代码,我可以看到完成处理程序几乎立即触发,在有时间动画之前删除约束.在NSAnimationContext上设置持续时间无效.

知道我在这里做错了什么吗?

小智 17

您必须先设置完成处理程序,然后才将消息发送到动画制作代理.否则,似乎在动画开始后设置完成处理程序会立即触发它,并在动画有时间结束之前删除常量.我刚刚用一段简单的代码检查了这个:

[NSAnimationContext beginGrouping];
NSAnimationContext.currentContext.duration = animagionDuration;
NSAnimationContext.currentContext.completionHandler = ^{
  [self removeConstraint:collapseConstraint];
};
[collapseConstraint.animator setConstant:expandedHeight];
Run Code Online (Sandbox Code Playgroud)

[NSAnimationContext endGrouping]; 这非常有效,但如果您之后设置了完成处理程序-setConstant:,则动画无法运行.


Rob*_*ger 13

我同意,这很奇怪,很可能是一个bug.我肯定会这样报告,因为据我所知,这应该有效.

我能够通过使用NSAnimationContext类方法+runAnimationGroup:completionHandler:而不是beginGroupingendGrouping语句来使它工作:

[NSAnimationContext runAnimationGroup:^(NSAnimationContext* context){
    [constraint.animator setConstant:self.width];   
} completionHandler:^(void){
    [theView removeConstraint:constraint];
    NSLog(@"completed");
}];
Run Code Online (Sandbox Code Playgroud)