61

CABasicAnimation画像ビューの移動とサイズ変更に使用しています。画像ビューをスーパービューに追加し、アニメーション化してから、スーパービューから削除したいと思います。

これを実現するために、私は自分のデリゲートコールをリッスンしCAAnimationGroupています。呼び出されるとすぐに、スーパービューからイメージビューを削除します。

問題は、スーパービューから削除される前に、画像が最初の場所で点滅することがあることです。この動作を回避するための最良の方法は何ですか?

CAAnimationGroup *animGroup = [CAAnimationGroup animation];
    animGroup.animations = [NSArray arrayWithObjects:moveAnim, scaleAnim, opacityAnim, nil];
    animGroup.duration = .5;
    animGroup.delegate = self;
    [imageView.layer addAnimation:animGroup forKey:nil];
4

3 に答える 3

189

アニメーションをレイヤーに追加しても、アニメーションはレイヤーのプロパティを変更しません。代わりに、システムはレイヤーのコピーを作成します。元のレイヤーはモデルレイヤーと呼ばれ、複製はプレゼンテーションレイヤーと呼ばれます。アニメーションが進むにつれてプレゼンテーション層のプロパティは変化しますが、モデル層のプロパティは変更されません。

アニメーションを削除すると、システムはプレゼンテーションレイヤーを破棄し、モデルレイヤーのみを残し、モデルレイヤーのプロパティがレイヤーの描画方法を制御します。したがって、モデルレイヤーのプロパティが、プレゼンテーションレイヤーのプロパティの最終的なアニメーション値と一致しない場合、レイヤーはアニメーションの前の外観に即座にリセットされます。

これを修正するには、モデルレイヤーのプロパティをアニメーションの最終値に設定してから、アニメーションをレイヤーに追加する必要がありますレイヤープロパティを変更すると、プロパティに暗黙のアニメーションが追加される可能性があり、明示的に追加するアニメーションと競合する可能性があるため、この順序で実行する必要があります。明示的なアニメーションが暗黙的なアニメーションをオーバーライドすることを確認する必要があります。

では、これをどのように行うのですか?基本的なレシピは次のようになります。

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = [NSValue valueWithCGPoint:myLayer.position];
layer.position = newPosition; // HERE I UPDATE THE MODEL LAYER'S PROPERTY
animation.toValue = [NSValue valueWithCGPoint:myLayer.position];
animation.duration = .5;
[myLayer addAnimation:animation forKey:animation.keyPath];

私はアニメーショングループを使用したことがないので、何を変更する必要があるのか​​正確にはわかりません。各アニメーションをレイヤーに個別に追加するだけです。

+[CATransaction setCompletionBlock:]また、アニメーションのデリゲートを使用するよりも、このメソッドを使用して1つまたは複数のアニメーションの完了ハンドラーを設定する方が簡単だと思います。トランザクションの完了ブロックを設定してから、アニメーションを追加します。

[CATransaction begin]; {
    [CATransaction setCompletionBlock:^{
        [self.imageView removeFromSuperview];
    }];
    [self addPositionAnimation];
    [self addScaleAnimation];
    [self addOpacityAnimation];
} [CATransaction commit];
于 2012-07-17T03:45:10.313 に答える
32

CAAnimationsは、完了すると自動的に削除されます。これを制御するプロパティがありますremovedOnCompletion。これをに設定する必要がありNOます。

fillModeさらに、アニメーションの継続時間の前後の動作を制御するものとして知られているものがあります。これはで宣言されたプロパティですCAMediaTiming(にCAAnimation準拠しています)。これをに設定する必要がありkCAFillModeForwardsます。

これらの両方の変更により、アニメーションは完了後も持続するはずです。ただし、これらをグループで変更する必要があるのか​​、グループ内の個々のアニメーションで変更する必要があるのか​​、あるいはその両方で変更する必要があるのか​​はわかりません。

于 2012-07-17T03:45:39.027 に答える
2

これが誰かを助けるかもしれないSwiftの例です

グラデーションレイヤーのアニメーションです。プロパティをアニメートしてい.locationsます。

@robMayoffの回答が完全に説明している重要なポイントは、次のとおりです。

驚いたことに、レイヤーアニメーションを実行するときは、アニメーションを開始する前に、最初に最終的な値を実際に設定します。

アニメーションが際限なく繰り返されるため、以下は良い例です。

アニメーションが際限なく繰り返される場合、「アニメーション化する前に値を設定するのを忘れる」という古典的な間違いを犯すと、アニメーション間に「フラッシュ」が発生することがあります。

var previousLocations: [NSNumber] = []
...

func flexTheColors() { // "flex" the color bands randomly
    
    let oldValues = previousTargetLocations
    let newValues = randomLocations()
    previousTargetLocations = newValues
    
    // IN FACT, ACTUALLY "SET THE VALUES, BEFORE ANIMATING!"
    theLayer.locations = newValues
    
    // AND NOW ANIMATE:
    CATransaction.begin()
    
    // and by the way, this is how you endlessly animate:
    CATransaction.setCompletionBlock{ [weak self] in
        if self == nil { return }
        self?.animeFlexColorsEndless()
    }
    
    let a = CABasicAnimation(keyPath: "locations")
    a.isCumulative = false
    a.autoreverses = false
    a.isRemovedOnCompletion = true
    a.repeatCount = 0

    a.fromValue = oldValues
    a.toValue = newValues
    
    a.duration = (2.0...4.0).random()
    
    theLayer.add(a, forKey: nil)
    CATransaction.commit()
}

以下は、新しいプログラマーのために何かを明確にするのに役立つかもしれません。私のコードではこれを行うことに注意してください:

    // IN FACT, ACTUALLY "SET THE VALUES, BEFORE ANIMATING!"
    theLayer.locations = newValues
    
    // AND NOW ANIMATE:
    CATransaction.begin()
    ...set up the animation...
    CATransaction.commit()

ただし、他の回答のコード例では、次のようになります。

    CATransaction.begin()
    ...set up the animation...
    // IN FACT, ACTUALLY "SET THE VALUES, BEFORE ANIMATING!"
    theLayer.locations = newValues
    CATransaction.commit()

「アニメーション化する前に値を設定する」コード行の位置について。..

その行を実際にコードのbegin-commit行の「内側」に配置することは実際には完全にOKです。の前にそれを行う限り.commit()

新しいアニメーターを混乱させる可能性があるため、これについてのみ言及します。

于 2017-12-10T18:40:24.077 に答える