NSLayoutConstraint.constant忽略动画



我正在为我的一个应用程序创建一个自动布局友好的拆分视图类。它的各种功能之一是,它可以折叠窗格,并可以为它们的折叠设置动画,就像你可能见过的NSSplitView一样

由于我使用约束,我通过在窗格上放置所需的宽度=(当前宽度)约束来实现这一点,然后以动画方式将约束的常量设置为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;
}

这个效果很好。不幸的是,稍后扩展窗格效果不佳。

- (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;
}

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

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

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

[NSAnimationContext beginGrouping];
NSAnimationContext.currentContext.duration = animagionDuration;
NSAnimationContext.currentContext.completionHandler = ^{
  [self removeConstraint:collapseConstraint];
};
[collapseConstraint.animator setConstant:expandedHeight];

[NSIM上下文endGrouping];这非常有效,但如果在-setConstant:之后设置完成处理程序,则动画将无法运行。

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

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

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

完成处理程序立即启动,因为它认为没有任何动画需要运行。我会检查并确认您创建的动画仍然附着到视图中。默认情况下,CABasicAnimation通过从CAAnimation继承的removedOnCompletion属性(默认情况下设置为YES)设置为在完成时删除自身。

你会想要

anim.removedOnCompletion = NO;

我自己刚刚掌握了这些东西,所以这可能是一个天真的分析,但:

在我看来,你是在约束的属性上指定动画(在你的其他块中),但在动画有机会运行之前,立即将对约束的引用设置为零(可能会释放它)。

我希望您希望从动画完成块内或由动画完成块触发将hiddenConstraint设置为nil。

请注意,如果我很可能错了,我会感谢你说一两句为什么能帮助我更好地理解它:)

相关内容

  • 没有找到相关文章

最新更新