17

アプリケーションの1つに対して、自動レイアウトに適した分割ビュークラスを作成しています。そのさまざまな機能の中には、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;
}

これは美しく機能します。残念ながら、後でペインを拡張してもうまくいきません。

- (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に期間を設定しても効果はありません。

私がここで間違っている可能性があることについて何か考えはありますか?

4

4 に答える 4

17

最初に完了ハンドラーを設定してから、メッセージをアニメータープロキシに送信する必要があります。それ以外の場合は、アニメーションの開始後に完了ハンドラーを設定するとすぐに起動し、アニメーションが終了する前に定数が削除されるようです。簡単なコードでこれを確認しました。

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

[NSAnimationContext endGrouping]; これは完全に機能しますが、後に完了ハンドラーを設定する-setConstant:と、アニメーションを実行する機会がありません。

于 2012-04-01T05:15:35.353 に答える
13

私は同意します、これはかなり奇妙で、バグかもしれません。私の知る限り、これはうまくいくはずなので、私は間違いなくそのように報告します。

andステートメントの代わりにNSAnimationContextclassメソッドを使用することで、それを機能させることができました。+runAnimationGroup:completionHandler:beginGroupingendGrouping

[NSAnimationContext runAnimationGroup:^(NSAnimationContext* context){
    [constraint.animator setConstant:self.width];   
} completionHandler:^(void){
    [theView removeConstraint:constraint];
    NSLog(@"completed");
}];
于 2012-03-17T01:03:41.417 に答える
3

実行する必要のあるアニメーションがないと判断したため、完了ハンドラーはすぐに起動します。作成したアニメーションがまだビューにアタッチされていることを確認します。デフォルトでは、CABasicAnimationは、CAAnimationから継承するremovedOnCompletionプロパティ(デフォルトではYESに設定されています)を使用して、完了時に自身を削除するように設定されています。

あなたがしたい

anim.removedOnCompletion = NO;
于 2012-03-14T19:50:47.880 に答える
1

私は自分でこのようなものを理解し始めているので、これは素朴な分析かもしれませんが:

制約のプロパティ(elseブロック内)でアニメーションを指定しているように見えますが、アニメーションを実行する前に、制約への参照をすぐにnilに設定します(解放する可能性があります)。

アニメーション完了ブロック内から、またはアニメーション完了ブロックによってトリガーされて、hiddenConstraintをnilに設定することをお勧めします。

おそらく、私が間違っている場合は、それをよりよく理解するのに役立つ理由について一言か二言いただければ幸いです:)

于 2012-03-14T14:09:45.743 に答える