1

私はアニメーションの初心者で、数日間 CoreAnimation を試しています。この質問が意味をなさない場合は、遠慮なく警告してください。ただし、次のことを達成しようとしています。私は3つのオブジェクトを持っています:

  • 1つは画像であり、特定のパターンに従って移動する必要があります
  • 1 つは 2 つの画像を交換する UIImage である必要があります
  • 1 つは、内容が変化するテキスト (CATextLayer?) である必要があります。

3 つのアクションは同期して発生する必要があります。

例として、-1 と +1 の間で振動する ECG のような正弦波関数を示すプログラムについて考えてみましょう。最初の画像は、現在の値 (-1、-0.9、-0.8、...) に従って移動します。 0、+0.1、+0.2、... 1)、スワップ画像は正の値の場合は「+」、負の値の場合は「-」を示し、テキストは「正」と「負」の間で交互に表示されます。

CAAnimationGroup を試してみましたが、明らかに何かが欠けています。いくつかのコード:

{
    // image that moves
    CALayer *img1 = [CALayer layer];
    img1.bounds = CGRectMake(0, 0, 20, 20);
    img1.position = CGPointMake(x1,y1);
    UIImage *img1Image = [UIImage imageNamed:@"image.png"];
    img1.contents = (id)img1Image.CGImage;

    // image that changes 
    CALayer *swap = [CALayer layer];
    swap.bounds = CGRectMake(0, 0, 30, 30);
    swap.position = CGPointMake(x2,y2);
    NSString* nameswap = @"img_swap_1.png"
    UIImage *swapImg = [UIImage imageNamed:nameswap];

    // text
    CATextLayer *text = [CATextLayer layer];
    text.bounds = CGRectMake(0, 0, 100, 100);
    text.position = CGPointMake(x3,y3);
    text.string = @"Text";


    // create animations
    CGFloat duration = 0.2;
    CGFloat totalDuration = 0.0;
    CGFloat start = 0;

    NSMutableArray* animarray = [[NSMutableArray alloc] init];
    NSMutableArray* swapanimarray = [[NSMutableArray alloc] init];
    NSMutableArray* textanimarray = [[NSMutableArray alloc] init];

    float prev_x = 0;
    float prev_y = 0;

    // I get my values for moving the object
    for (NSDictionary* event in self.events) {

            float actual_x = [[event valueForKey:@"x"] floatValue];
            float actual_y = [[event valueForKey:@"y"] floatValue];


            // image move animation
            CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];            
            CGPoint startPt = CGPointMake(prev_x,prev_y);
            CGPoint endPt = CGPointMake(actual_x, actual_y);
            anim.duration = duration;
            anim.fromValue = [NSValue valueWithCGPoint:startPt];
            anim.toValue = [NSValue valueWithCGPoint:endPt];
            anim.beginTime = start;
            anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];            
            [animarray addObject:anim];


            // image swap animation
                        CABasicAnimation *swapanim = [CABasicAnimation animationWithKeyPath:@"contents"];

            swapanim.duration = duration;
            swapanim.beginTime = start;

            NSString* swapnamefrom = [NSString stringWithFormat:@"%@.png", prev_name];
            NSString* swapnameto = [NSString stringWithFormat:@"%@.png", current_name];
            UIImage *swapFromImage = [UIImage imageNamed:swapnamefrom];
            UIImage *swapToImage = [UIImage imageNamed:swapnameto];
            swapanim.fromValue = (id)(swapFromImage.CGImage);
            swapanim.toValue = (id)(swapToImage.CGImage);
            swapanim.fillMode = kCAFillModeForwards;
            swapanim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];      
            [swapanimarray addObject:swapanim];

            //text animation
            CABasicAnimation *textanim = [CABasicAnimation animationWithKeyPath:@"contents"];            
            textanim.duration = duration;
            textanim.fromValue = @"Hey";
            textanim.toValue = @"Hello";
            textanim.beginTime = start;
            [textanimarray addObject:textanim];


            // final time settings
            prev_x = actual_x;
            prev_y = actual_y;
            start = start + duration;
            totalDuration = start + duration;

        }

    }


    CAAnimationGroup* group = [CAAnimationGroup animation];
    [group setDuration:totalDuration]; 
    group.removedOnCompletion = NO;
    group.fillMode = kCAFillModeForwards;
    [group setAnimations:animarray];

    CAAnimationGroup* swapgroup = [CAAnimationGroup animation];
    [swapgroup setDuration:totalDuration]; 
    swapgroup.removedOnCompletion = NO;
    swapgroup.fillMode = kCAFillModeForwards;
    [swapgroup setAnimations:swapanimarray];

    CAAnimationGroup* textgroup = [CAAnimationGroup animation];
    [textgroup setDuration:totalDuration]; 
    textgroup.removedOnCompletion = NO;
    textgroup.fillMode = kCAFillModeForwards;
    [textgroup setAnimations:textanimarray];

    [ball addAnimation:group forKey:@"position"];
    [swap addAnimation:flaggroup forKey:@"position"];
    [text addAnimation:textgroup forKey:@"contents"];

    [self.layer addSublayer:ball];
    [self.layer addSublayer:swap];
    [self.layer addSublayer:text];


}

さて...問題:

1) スワップ イメージはスワップごとに元に戻ります。したがって、A->B を交換すると、予想される継続時間内に A から B に移動することがわかりますが、その後 A に戻ります。これについて SO で多くのスレッドを読みましたが、機能させることができませんでした.

2) テキストレイヤーの文字列をタイミングを合わせて変更する...これはこのインフラストラクチャで可能ですか? 基本的に、例で説明されているように、最初の画像が移動するとすぐにテキストとスワップ画像を変更しようとしています。

3) CABasicAnimation のデリゲートを設定しても効果はありませんが、CAAnimationGroup には効果があります。その結果、アニメーションごとに、グループ全体だけで animationDidStop のようなイベントを管理することはできません。そうする別の方法はありますか?

4) 3) に続いて、CAAnimationGroup を使用して、イベントをインターセプトして停止/開始動作を作成することは可能ですか? 再生/停止ボタンが必要で、アニメーションを中断したところから再開したいとしましょう。

決定的な質問として、誰かが同様のことをしたかどうか、そして最も重要なのは、この方法 (CAAnimationGroup を使用) が実際に進むべき道なのか、それとも CAKeyFrameAnimation などを使用する方が良いのかを知りたいだけです。

4

1 に答える 1

1

いくつかの回避策はありますが、問題を解決することができました。

1) ここでのトリックは、

removedOnCompletion = NO;
fillMode = kCAFillModeForwards;

CAAnimationGroup ではなく、すべてのアニメーションに割り当てる必要があります。

2) これには、CATextLayer に対して別のアニメーションを決定し、「文字列」プロパティをアニメーション化する必要があります。この場合、「コンテンツ」キー値を除いて、コードは正しかったです。

[text addAnimation:textgroup forKey:@"contentAnimate"];

または、ポイント 3 を参照してください。コールバック操作方法により、label.text を変更できます。

3) これを行う唯一の方法は、実際には CAAnimationGroup を使用せず、CABasicAnimation のシーケンスをセットアップすることです。一般的なスキーマは次のとおりです。関数で最初の CABasicAnimation を作成し、デリゲートを割り当てます。animationDidStop メソッドで、CABasicAnimation を作成する関数にコールバックを追加します。このようにして、それぞれのアニメーションが作成されます。同時に、これにより、アニメーション内の特定のイベントを傍受して反応することができます。

-(void)performNextAnimation:(int)index {
    // ... this gives for granted you have an object for #index ...
    NSDictionary* thisEvent = [self.events objectAtIndex:index];
    float prev_x = [thisEvent valueForKey:@"prev_x"];
    float prev_y = [thisEvent valueForKey:@"prev_x"];
    float actual_x = [thisEvent valueForKey:@"prev_x"];
    float actual_y = [thisEvent valueForKey:@"prev_x"];
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];            
    GPoint startPt = CGPointMake(prev_x,prev_y);
    CGPoint endPt = CGPointMake(actual_x, actual_y);
    anim.duration = 0.5;
    anim.fromValue = [NSValue valueWithCGPoint:startPt];
    anim.toValue = [NSValue valueWithCGPoint:endPt];
    anim.beginTime = start;
    [anim setDelegate:self];
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];            
    [object addAnimation:anim forKey:@"position"];
}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
    // ... your conditions go here ...
    // ... your actions go here ... 
    //     e.g. set label.text
    [self performNextAnimation];
}

4) 3 に続き、CAAnimationGroup ではこれができません。ドキュメントを読むと、CAAnimationGroup は、各イベントが時間の前進を表すシーケンスに使用することを意図していないと言えます (このためには、CAKeyFrameAnimation または CABasicAnimation のシーケンスをコールバック関数と共に使用する必要があります)。CAAnimationGroup は、(CATransaction と同様に) 全か無かで実行されるリンクされたアニメーションを対象としています。

于 2012-03-07T11:27:56.887 に答える