4

私はアニメーションコールのバッチを持っており、配列を反復して呼び出されます。これらの呼び出しはすべてカプセル化アニメーションブロック内にネストされ、効果的に並行して実行されます。入れ子にされたアニメーションがすべて完了したら、私はただ起動したいだけで完了ブロックを持っています。
問題はネストされたアニメーションの期間が不明であるため、最後に終了するコールを計算してこのコールの完了ブロックを設定することはできません。同様に、私は期間を計算することができず、完了ブロックで遅延呼び出しを使用することはできません。
この例を明確にすることができればうれしいことです。これは私が何をしようとしているの(非常に単純化された)バージョンです:UIView animateWithDuration呼び出しのネストされたグループに対して単一の補完ブロックを呼び出す方法は?

-(void) animateStuff:(CGFloat)animationDuration withCompletionBlock:(void) (^)(BOOL)completionBlock { 

// encapsulating animation block so that all nested animations start at the same time 
[UIView animateWithDuration:animationDuration animations:^{ 

    for(MyObject* object in self.array) { 
     // this method contains other [UIView animateWithDuration calls... 
     [self animationOfUnknownDurationWithObject:object nestedCompletionBlock:^(BOOL finished) { 
      // what I effectively what here is: 
      if(last animation to finish) { 
       completionBlock(YES); 
      } 
     }]; 
    } 

}]; // cannot use the completion block for the encapsulating animation block, as it is called straight away 
} 

、ここで説明したようdispatch_groupsと非同期呼び出しを使用することによって提供される機能: http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html


は明らかに理想的であるが、しかし、UIView animateWithDuration呼び出し自体は非同期呼び出しであるため、dispatch_group_async内で呼び出すと正しく動作しません。
__blockカウント変数がnestedCompletionBlockの中でどれが最終のものかを判断する方法として減分されるようなことができることはわかっていますが、私がこれを持っているコードではかなり面倒です(上記は単純な例です)。
これを行う良い方法はありますか?おそらく、animateWithDurationを同期的に行う何らかの方法で、dispatch_group_asyncで動作するようにしますか?

iOS 5.0で作業しています。

UPDATE:あなたの答えのためのRob-
ありがとう@


!これは私の問題をほぼ解決しています。以前はCATransactionを見ていませんでした。質問する前に少し深く掘り下げていたはずです。 :)
しかし、1つの問題が残っています。前に述べたように、私の例は単純化され、残っている問題は、アニメーションが入れ子になったトランザクション内にインクルードする必要のある完了ブロック(つまり連鎖アニメーション)をネストしていることから発生します。
ですから、例えば、私は次のコードを実行した場合:

2011-12-08 15:11:35.828 testProj [51550:F803]アニメーションの第一段階
私は次の出力を得る

-(void) testAnim { 
NSArray* testArray = [NSArray arrayWithObjects:self.redView, self.blueView, nil]; 

[CATransaction begin]; { 
    [CATransaction setCompletionBlock:^{ 
     NSLog(@"All animations complete!"); 
    }]; 

    for(UIView* view in testArray) { 
     [CATransaction begin]; { 

      [CATransaction setCompletionBlock:^{ 

       [CATransaction begin]; { 
        [CATransaction setCompletionBlock:^{ 
         NSLog(@"2nd stage complete"); 
        }]; 

        NSLog(@"Animation 2nd stage"); 
        [UIView animateWithDuration:2 animations:^{ 
         setX(view, 100); 
        }]; 
       } [CATransaction commit]; 
      }]; 

      NSLog(@"animation 1st stage"); 
      [UIView animateWithDuration:2 animations:^{ 
       setX(view, 150); 
      }]; 
     }[CATransaction commit]; 
    } 

} [CATransaction commit]; 
} 

を2011-12-08 15:11:35.831 testProj [51550:F803】アニメーション第1ステージ
2011-12-08 15:11:37.832 testProj [51550:F803]アニメ第2段階
2011-12-08 15:11 :37.834 testProj [51550:f803]アニメーション第2ステージ
2011-12-08 15:11:37.848 testProj [51550:f803]すべてのアニメーションが完了!
2011-12-08 15:11:39.834 testProj [51550:F803]完全な2段目
2011-12-08 15:11:39.851 testProj [51550:F803】2段目完全

何一方I必要なのは「すべてのアニメーションが完了しました!」です。すべての内部操作が終了した後にのみ起動されるイベントです。
おそらく、クラスレベルで完了ブロックを設定しているだけで、各ブロックを特定の操作に結び付けることができないという事実と関係していますか?
いずれにしても、私はまだそれを得ていません。また、UIView animateWithDurationを使用して、独自の補完ブロック引数でオーバーロードすると、同じ問題が発生します。
アイデア?

答えて

3

CATransactionにすべてをラップし、トランザクションのcompletionBlockを設定します。これは私のテストでした:

static void setX(UIView *view, CGFloat x) 
{ 
    CGRect frame = view.frame; 
    frame.origin.x = x; 
    view.frame = frame; 
} 

- (IBAction)startAnimation:(id)sender { 
    label.text = @"Animation starting!"; 
    setX(redView, 0); 
    setX(blueView, 0); 
    [CATransaction begin]; { 
     [CATransaction setCompletionBlock:^{ 
      label.text = @"Animation complete!"; 
     }]; 
     [UIView animateWithDuration:1 animations:^{ 
      setX(redView, 300); 
     }]; 
     [UIView animateWithDuration:2 animations:^{ 
      setX(blueView, 300); 
     }]; 
    } [CATransaction commit]; 
} 

まだいない場合は、QuartzCoreフレームワークを追加する必要があります。

更新された質問について:完了ブロックから新しいアニメーションを作成しているため、これらの新しいアニメーションは元のトランザクションの一部ではないため、元のトランザクションは完了するまで待機しません。

+[UIView animateWithDuration:delay:options:animations:completion:]を適切なタイミングで後のアニメーションを開始する遅延値で使用して、後のアニメーションを元のトランザクションの一部として開始するのが最も簡単です。

+0

回答ありがとうございますが、私はまだいくつかの問題があります。 編集した質問を確認できれば幸いです。 事前に感謝... –

1

お手伝いがあります。

-(void) testAnim2 { 
    // NSArray* testArray = [NSArray arrayWithObjects:self.redView, self.blueView, nil]; 



    [CATransaction begin]; { 
     [CATransaction setCompletionBlock:^{ 

      [CATransaction begin]; { 

       [CATransaction setCompletionBlock:^{ 
        NSLog(@"All completion block"); 

       }]; 


      }[CATransaction commit]; 

      NSLog(@"animation 2nd stage"); 
      [UIView animateWithDuration:2 animations:^{ 
       setX(blueView, 150); 
      }]; 


     }]; 
     NSLog(@"animation 1st stage"); 
     [UIView animateWithDuration:2 animations:^{ 
      setX(redView, 150); 


     }]; 


    } [CATransaction commit]; 
} 
関連する問題