13

何か初歩的なことを見落としているような気がしますが、インターネットで間違っていること以外にそれを見つける良い方法はありますか?

私はかなり基本的なUIを持っています。私のビューUIViewControllerはサブクラスであり、そのサブクラス+layerClassCAGradientLayer. ユーザーのアクションに応じて、いくつかの UI 要素を移動し、背景のグラデーションの値を変更する必要があります。コードは次のようになります。

[UIView animateWithDuration:0.3 animations:^{
  self.subview1.frame = CGRectMake(...);
  self.subview2.frame = CGRectMake(...);
  self.subview2.alpha = 0;

  NSArray* newColors = [NSArray arrayWithObjects:
                         (id)firstColor.CGColor,
                         (id)secondColor.CGColor,
                         nil];
  [(CAGradientLayer *)self.layer setColors:newColors];
}];

問題は、このブロックでサブビューに加えた変更はうまくアニメーション化されますが (物が移動してフェードします)、グラデーションの色への変更はそうではありません。交換するだけです。

ドキュメントには、アニメーション ブロック内の Core Animation コードはブロックのプロパティ (期間、イージングなど) を継承しないと書かれています。しかし、アニメーション トランザクションがまったく定義されていないということでしょうか。(ドキュメントの意味は、デフォルトのアニメーションが得られるように思われますが、私は何も得られません。)

これを機能させるには明示的に使用する必要がありますか? CAAnimation(もしそうなら、なぜですか?)

4

2 に答える 2

13

ここでは 2 つのことが行われているようです。1 つ目は (Travis が正しく指摘し、ドキュメントにも記載されているように)、UIKit のアニメーションは、CALayerプロパティの変更に適用される暗黙のアニメーションに影響を与えていないように見えるということです。これは奇妙だと思います (UIKitはCore Animation を使用しているに違いありません) が、実際にはそうなっています

その問題の回避策は次のとおりです(おそらく非常にばかげていますか?)。

  NSTimeInterval duration = 2.0; // slow things down for ease of debugging
  [UIView animateWithDuration:duration animations:^{
    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];

    // ... do stuff to things here ...

    [CATransaction commit];
  }];

もう 1 つの重要な点は、このグラデーション レイヤーがビューのレイヤーであることです。つまり、私のビューはレイヤーのデリゲートです (グラデーション レイヤーが単なるサブレイヤーの場合、デリゲートはありません)。そして、イベントのリターンのUIView実装。(おそらく、UIView アニメーションの特定のリストにないすべてのイベント。)-actionForLayer:forKey:NSNull"colors"

ビューに次のコードを追加すると、色の変化が期待どおりにアニメーション化されます。

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{
  id<CAAction> action = [super actionForLayer:layer forKey:event];
  if( [@"colors" isEqualToString:event]
      && (nil == action || (id)[NSNull null] == action) ) {
    action = [CABasicAnimation animationWithKeyPath:event];
  }
  return action;
}
于 2012-02-28T17:46:50.663 に答える
1

CALayerの値を変更するため、明示的なCAAnimationsを使用する必要があります。UIViewAnimationsはUIViewプロパティで機能しますが、CALayerのプロパティでは直接機能しません...

実際には、CABasicAnimationを使用して、そのプロパティfromValueにアクセスできるようにする必要がありtoValueます。

次のコードが機能するはずです。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [UIView animateWithDuration:2.0f
                          delay:0.0f
                        options:UIViewAnimationCurveEaseInOut
                     animations:^{
                         CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"colors"];
                         animation.duration = 2.0f;
                         animation.delegate = self;
                         animation.fromValue = ((CAGradientLayer *)self.layer).colors;
                         animation.toValue = [NSArray arrayWithObjects:(id)[UIColor blackColor].CGColor,(id)[UIColor whiteColor].CGColor,nil];
                         [self.layer addAnimation:animation forKey:@"animateColors"];
                     }
                     completion:nil];
}

-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    NSString *keyPath = ((CAPropertyAnimation *)anim).keyPath;
    if ([keyPath isEqualToString:@"colors"]) {
        ((CAGradientLayer *)self.layer).colors = ((CABasicAnimation *)anim).toValue;
    }
}

CAAnimationsには、アニメーションの完了後にプロパティの値を明示的に設定する必要があるというトリックがあります。

これを行うには、デリゲートを設定します。この場合は、アニメーションを呼び出すオブジェクトにデリゲートを設定し、そのanimationDidStop:finished:メソッドをオーバーライドして、CAGradientLayerの色の設定を最終的な値に含めます。

animationDidStop:また、アニメーションのプロパティにアクセスするには、メソッドで少しキャストする必要があります。

于 2012-02-25T08:50:06.853 に答える