2

というサブレイヤーを持つビューがありますspecialLayer。不透明度の暗黙的なアニメーションは、次のように無効になります。

self.specialLayer.actions = [NSDictionary dictionaryWithObjectsAndKeys:
                                            [NSNull null], @"opacity", nil];

このサブレイヤーにアクセスする方法は 2 つだけです。

- (void)touchDown {
    self.specialLayer.opacity = 0.25f;
}

- (void)touchUp {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.fromValue = [NSNumber numberWithFloat:self.specialLayer.opacity];
    animation.toValue = [NSNumber numberWithFloat:1.0];
    animation.duration = 0.5;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    [self.specialLayer addAnimation:animation forKey:@"opacity"];
}

これが起こります:

1) ユーザーがボタンを押して (保持)、-touchDown が呼び出されます。specialLayer の不透明度が瞬時に 0.25 になる

2) ユーザーがボタンを離すと、-touchUp が呼び出されます。specialLayer の不透明度がアニメーションで 1.0 に戻る

このシーケンスは 1 回だけ機能します。

3) ユーザーがもう一度ボタンを押して (保持)、-touchDown が呼び出されます。しかし、specialLayer の不透明度は画面上で変化しません! self.specialLayer.opacity = 0.25f;呼び出されても何も起こりません。不透明度は 1.0f のままのようです。

4) ユーザーが指を離すと、-touchUp が呼び出されます。specialLayer の不透明度は 0.25 にジャンプし、そこから 1.0f にアニメーション化されます。

メソッドがこの順序で呼び出されることを確認するために、NSLog で確認しました。彼らはそうします。

アニメーション コードのコメントを解除し、不透明度を直接 1.0 に設定すると、その後の直接的な不透明度の変更がすぐに有効になります。問題を引き起こすのは間違いなく CABasicAnimation です。暗黙的なアニメーションを無効にするコードを削除しても、この問題には影響しません。

ここで何が起こっているのか、一生理解できない。opacity に CABasicAnimation を追加した後、しばらくして設定した opacity 値が CALayer に反映されないのはなぜですか? これはバグですか?

私は何を間違っていますか?

4

1 に答える 1

8

アニメーションremovedOnCompletionをに設定しNOます。これは、アニメーションが完了しても、アニメーションはレイヤー上にとどまり、opacityレンダリングの目的での値を制御することを意味します。このコードをもう一度呼び出すと、新しいアニメーションが古いアニメーションに置き換わり、ジャンプが発生します(これは、新しく設定さ0.25fれたアニメーションを開始点として使用しているためです)。

removedOnCompletion解決策は、への設定を停止することNOです。代わりに、アニメーションを追加すると同時に、レイヤーの実際の不透明度をアニメーションの端点と同じ値に設定する必要があります。

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
// you can omit fromValue since you're setting it to the layer's opacity
// by omitting fromValue, it uses the current value instead. Just remember
// to not change layer.opacity until after you add the animation to the layer
animation.toValue = [NSNumber numberWithFloat:1];
animation.duration = 0.5;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[layer addAnimation:animation forKey:@"opacity"];
layer.opacity = 1; // or layer.opacity = [animation.toValue floatValue];

これは、レイヤーレンダリングの仕組みによるものです。CoreAnimationがレイヤーツリーを画面にレンダリングすると、モデルツリーがコピーされ、プレゼンテーションツリーと呼ばれるものが生成されます。これは、すべてのレイヤーをコピーしてから、すべてのアニメーションを適用することによって行われます。そのため、レイヤー上の各アニメーションを調べ、時間をタイミング関数にプラグインし、結果の進行状況をfrom / to値間の補間にプラグインし、その最終値をプレゼンテーションレイヤーのプロパティに適用します。

したがって、アニメーションをレイヤーに永続的に残すと、このアニメーションは、キーの実際のモデル値が何であれ、常にオーバーライドされます。何度変更layer.opacityしても、コントロールするアニメーションopacityはプレゼンテーションの目的で常に値を上書きします。

これと同じ理由でlayer.opacity、アニメーションが優先されるため、アニメーションを追加した後に任意の値に設定できます。アニメーションが削除された場合(デフォルトではアニメーションの完了時に発生します)にのみ、そのプロパティのモデル値が再度使用されます。

于 2012-09-13T19:46:01.340 に答える